libnetwork/cni: fix CNIResultToStatus conversion logic

When we read the cni result we should loop over the interfaces and then
the ips. If we only loop over ips we will miss interfaces that have no
ips assigned. We also only care about interfaces created in the netns.

This is required for ipam driver none case, see the test case.

Signed-off-by: Paul Holzinger <pholzing@redhat.com>
This commit is contained in:
Paul Holzinger 2022-03-17 17:25:17 +01:00
parent e2dabcc352
commit 76fca332db
2 changed files with 109 additions and 21 deletions

View File

@ -125,35 +125,38 @@ func CNIResultToStatus(res cnitypes.Result) (types.StatusBlock, error) {
result.DNSSearchDomains = cniResult.DNS.Search
interfaces := make(map[string]types.NetInterface)
for _, ip := range cniResult.IPs {
if ip.Interface == nil {
// we do no expect ips without an interface
for intIndex, netInterface := range cniResult.Interfaces {
// we are only interested about interfaces in the container namespace
if netInterface.Sandbox == "" {
continue
}
if len(cniResult.Interfaces) <= *ip.Interface {
return result, errors.Errorf("invalid cni result, interface index %d out of range", *ip.Interface)
mac, err := net.ParseMAC(netInterface.Mac)
if err != nil {
return result, err
}
cniInt := cniResult.Interfaces[*ip.Interface]
netInt, ok := interfaces[cniInt.Name]
if ok {
netInt.Subnets = append(netInt.Subnets, types.NetAddress{
IPNet: types.IPNet{IPNet: ip.Address},
Gateway: ip.Gateway,
})
interfaces[cniInt.Name] = netInt
} else {
mac, err := net.ParseMAC(cniInt.Mac)
if err != nil {
return result, err
subnets := make([]types.NetAddress, 0, len(cniResult.IPs))
for _, ip := range cniResult.IPs {
if ip.Interface == nil {
// we do no expect ips without an interface
continue
}
interfaces[cniInt.Name] = types.NetInterface{
MacAddress: types.HardwareAddr(mac),
Subnets: []types.NetAddress{{
if len(cniResult.Interfaces) <= *ip.Interface {
return result, errors.Errorf("invalid cni result, interface index %d out of range", *ip.Interface)
}
// when we have a ip for this interface add it to the subnets
if *ip.Interface == intIndex {
subnets = append(subnets, types.NetAddress{
IPNet: types.IPNet{IPNet: ip.Address},
Gateway: ip.Gateway,
}},
})
}
}
interfaces[netInterface.Name] = types.NetInterface{
MacAddress: types.HardwareAddr(mac),
Subnets: subnets,
}
}
result.Interfaces = interfaces
return result, nil

View File

@ -830,6 +830,91 @@ var _ = Describe("run CNI", func() {
Expect(err).To(BeNil())
})
})
It("setup ipam driver none network", func() {
runTest(func() {
network := types.Network{
IPAMOptions: map[string]string{
types.Driver: types.NoneIPAMDriver,
},
}
network1, err := libpodNet.NetworkCreate(network)
Expect(err).To(BeNil())
intName1 := "eth0"
netName1 := network1.Name
setupOpts := types.SetupOptions{
NetworkOptions: types.NetworkOptions{
ContainerID: stringid.GenerateNonCryptoID(),
Networks: map[string]types.PerNetworkOptions{
netName1: {
InterfaceName: intName1,
},
},
},
}
res, err := libpodNet.Setup(netNSContainer.Path(), setupOpts)
Expect(err).To(BeNil())
Expect(res).To(HaveLen(1))
Expect(res).To(HaveKey(netName1))
Expect(res[netName1].Interfaces).To(HaveKey(intName1))
Expect(res[netName1].Interfaces[intName1].Subnets).To(HaveLen(0))
macInt1 := res[netName1].Interfaces[intName1].MacAddress
Expect(macInt1).To(HaveLen(6))
// check in the container namespace if the settings are applied
err = netNSContainer.Do(func(_ ns.NetNS) error {
defer GinkgoRecover()
i, err := net.InterfaceByName(intName1)
Expect(err).To(BeNil())
Expect(i.Name).To(Equal(intName1))
Expect(i.HardwareAddr).To(Equal(net.HardwareAddr(macInt1)))
addrs, err := i.Addrs()
Expect(err).To(BeNil())
// we still have the ipv6 link local address
Expect(addrs).To(HaveLen(1))
addr, ok := addrs[0].(*net.IPNet)
Expect(ok).To(BeTrue(), "cast address to ipnet")
// make sure we are link local
Expect(addr.IP.IsLinkLocalUnicast()).To(BeTrue(), "ip is link local address")
// check loopback adapter
i, err = net.InterfaceByName("lo")
Expect(err).To(BeNil())
Expect(i.Name).To(Equal("lo"))
Expect(i.Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
Expect(i.Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
return nil
})
Expect(err).To(BeNil())
err = libpodNet.Teardown(netNSContainer.Path(), types.TeardownOptions(setupOpts))
Expect(err).To(BeNil())
logString := logBuffer.String()
Expect(logString).To(BeEmpty())
// check in the container namespace that the interface is removed
err = netNSContainer.Do(func(_ ns.NetNS) error {
defer GinkgoRecover()
_, err := net.InterfaceByName(intName1)
Expect(err).To(HaveOccurred())
// check that only the loopback adapter is left
ints, err := net.Interfaces()
Expect(err).To(BeNil())
Expect(ints).To(HaveLen(1))
Expect(ints[0].Name).To(Equal("lo"))
Expect(ints[0].Flags & net.FlagLoopback).To(Equal(net.FlagLoopback))
Expect(ints[0].Flags&net.FlagUp).To(Equal(net.FlagUp), "Loopback adapter should be up")
return nil
})
Expect(err).To(BeNil())
})
})
})
Context("network setup test with networks from disk", func() {