Merge pull request #298 from s1061123/dev/macvlan-default-master

macvlan: make master config as optional
This commit is contained in:
Casey Callendrello 2019-04-30 15:47:51 +02:00 committed by GitHub
commit dbc86e4db2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 136 additions and 2 deletions

View File

@ -23,7 +23,7 @@ Since each macvlan interface has its own MAC address, it makes it easy to use wi
* `name` (string, required): the name of the network * `name` (string, required): the name of the network
* `type` (string, required): "macvlan" * `type` (string, required): "macvlan"
* `master` (string, required): name of the host interface to enslave * `master` (string, optional): name of the host interface to enslave. Defaults to default route interace.
* `mode` (string, optional): one of "bridge", "private", "vepa", "passthru". Defaults to "bridge". * `mode` (string, optional): one of "bridge", "private", "vepa", "passthru". Defaults to "bridge".
* `mtu` (integer, optional): explicitly set MTU to the specified value. Defaults to the value chosen by the kernel. * `mtu` (integer, optional): explicitly set MTU to the specified value. Defaults to the value chosen by the kernel.
* `ipam` (dictionary, required): IPAM configuration to be used for this network. * `ipam` (dictionary, required): IPAM configuration to be used for this network.

View File

@ -55,13 +55,36 @@ func init() {
runtime.LockOSThread() runtime.LockOSThread()
} }
func getDefaultRouteInterfaceName() (string, error) {
routeToDstIP, err := netlink.RouteList(nil, netlink.FAMILY_ALL)
if err != nil {
return "", err
}
for _, v := range routeToDstIP {
if v.Dst == nil {
l, err := netlink.LinkByIndex(v.LinkIndex)
if err != nil {
return "", err
}
return l.Attrs().Name, nil
}
}
return "", fmt.Errorf("no default route interface found")
}
func loadConf(bytes []byte) (*NetConf, string, error) { func loadConf(bytes []byte) (*NetConf, string, error) {
n := &NetConf{} n := &NetConf{}
if err := json.Unmarshal(bytes, n); err != nil { if err := json.Unmarshal(bytes, n); err != nil {
return nil, "", fmt.Errorf("failed to load netconf: %v", err) return nil, "", fmt.Errorf("failed to load netconf: %v", err)
} }
if n.Master == "" { if n.Master == "" {
return nil, "", fmt.Errorf(`"master" field is required. It specifies the host interface name to virtualize`) defaultRouteInterface, err := getDefaultRouteInterfaceName()
if err != nil {
return nil, "", err
}
n.Master = defaultRouteInterface
} }
return n, n.CNIVersion, nil return n, n.CNIVersion, nil
} }

View File

@ -399,4 +399,115 @@ var _ = Describe("macvlan Operations", func() {
}) })
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
It("configures and deconfigures a macvlan link with ADD/DEL, without master config", func() {
const IFNAME = "macvl0"
conf := `{
"cniVersion": "0.3.1",
"name": "mynet",
"type": "macvlan",
"ipam": {
"type": "host-local",
"subnet": "10.1.2.0/24"
}
}`
targetNs, err := testutils.NewNS()
Expect(err).NotTo(HaveOccurred())
defer targetNs.Close()
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNs.Path(),
IfName: IFNAME,
StdinData: []byte(conf),
}
// Make MASTER_NAME as default route interface
err = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
link, err := netlink.LinkByName(MASTER_NAME)
Expect(err).NotTo(HaveOccurred())
err = netlink.LinkSetUp(link)
Expect(err).NotTo(HaveOccurred())
var address = &net.IPNet{IP: net.IPv4(192, 0, 0, 1), Mask: net.CIDRMask(24, 32)}
var addr = &netlink.Addr{IPNet: address}
err = netlink.AddrAdd(link, addr)
Expect(err).NotTo(HaveOccurred())
// add default gateway into MASTER
dst := &net.IPNet{
IP: net.IPv4(0, 0, 0, 0),
Mask: net.CIDRMask(0, 0),
}
ip := net.IPv4(192, 0, 0, 254)
route := netlink.Route{LinkIndex: link.Attrs().Index, Dst: dst, Gw: ip}
err = netlink.RouteAdd(&route)
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())
var result *current.Result
err = originalNS.Do(func(ns.NetNS) error {
r, _, err := testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
result, err = current.GetResult(r)
Expect(err).NotTo(HaveOccurred())
Expect(len(result.Interfaces)).To(Equal(1))
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
Expect(len(result.IPs)).To(Equal(1))
return nil
})
Expect(err).NotTo(HaveOccurred())
// Make sure macvlan link exists in the target namespace
err = targetNs.Do(func(ns.NetNS) error {
defer GinkgoRecover()
link, err := netlink.LinkByName(IFNAME)
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().Name).To(Equal(IFNAME))
hwaddr, err := net.ParseMAC(result.Interfaces[0].Mac)
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().HardwareAddr).To(Equal(hwaddr))
addrs, err := netlink.AddrList(link, syscall.AF_INET)
Expect(err).NotTo(HaveOccurred())
Expect(len(addrs)).To(Equal(1))
return nil
})
Expect(err).NotTo(HaveOccurred())
err = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
err := testutils.CmdDelWithArgs(args, func() error {
return cmdDel(args)
})
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())
// Make sure macvlan link has been deleted
err = targetNs.Do(func(ns.NetNS) error {
defer GinkgoRecover()
link, err := netlink.LinkByName(IFNAME)
Expect(err).To(HaveOccurred())
Expect(link).To(BeNil())
return nil
})
Expect(err).NotTo(HaveOccurred())
})
}) })