From 08ff3b641341a1124db8ebb123f61b420fcb3328 Mon Sep 17 00:00:00 2001 From: Tomofumi Hayashi Date: Wed, 16 Sep 2020 15:09:00 +0900 Subject: [PATCH] ipvlan: make master config as optional This change makes ipvlan master parameter optional. Default to default route interface as macvlan does. Signed-off-by: Tomofumi Hayashi --- plugins/main/ipvlan/README.md | 2 +- plugins/main/ipvlan/ipvlan.go | 35 ++++++++++++++++++---- plugins/main/ipvlan/ipvlan_test.go | 48 +++++++++++++++++++++++++++++- 3 files changed, 78 insertions(+), 7 deletions(-) diff --git a/plugins/main/ipvlan/README.md b/plugins/main/ipvlan/README.md index 0df1d5ca..aa87469a 100644 --- a/plugins/main/ipvlan/README.md +++ b/plugins/main/ipvlan/README.md @@ -27,7 +27,7 @@ Because all ipvlan interfaces share the MAC address with the host interface, DHC * `name` (string, required): the name of the network. * `type` (string, required): "ipvlan". -* `master` (string, required unless chained): name of the host interface to enslave. +* `master` (string, optional): name of the host interface to enslave. Defaults to default route interface. * `mode` (string, optional): one of "l2", "l3", "l3s". Defaults to "l2". * `mtu` (integer, optional): explicitly set MTU to the specified value. Defaults to the value chosen by the kernel. * `ipam` (dictionary, required unless chained): IPAM configuration to be used for this network. diff --git a/plugins/main/ipvlan/ipvlan.go b/plugins/main/ipvlan/ipvlan.go index ba24b54e..19a69903 100644 --- a/plugins/main/ipvlan/ipvlan.go +++ b/plugins/main/ipvlan/ipvlan.go @@ -72,12 +72,18 @@ func loadConf(bytes []byte, cmdCheck bool) (*NetConf, string, error) { } if n.Master == "" { if result == nil { - return nil, "", fmt.Errorf(`"master" field is required. It specifies the host interface name to virtualize`) - } - if len(result.Interfaces) == 1 && result.Interfaces[0].Name != "" { - n.Master = result.Interfaces[0].Name + defaultRouteInterface, err := getDefaultRouteInterfaceName() + + if err != nil { + return nil, "", err + } + n.Master = defaultRouteInterface } else { - return nil, "", fmt.Errorf("chained master failure. PrevResult lacks a single named interface") + if len(result.Interfaces) == 1 && result.Interfaces[0].Name != "" { + n.Master = result.Interfaces[0].Name + } else { + return nil, "", fmt.Errorf("chained master failure. PrevResult lacks a single named interface") + } } } return n, n.CNIVersion, nil @@ -167,6 +173,25 @@ func createIpvlan(conf *NetConf, ifName string, netns ns.NetNS) (*current.Interf return ipvlan, nil } +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 cmdAdd(args *skel.CmdArgs) error { n, cniVersion, err := loadConf(args.StdinData, false) if err != nil { diff --git a/plugins/main/ipvlan/ipvlan_test.go b/plugins/main/ipvlan/ipvlan_test.go index 2da00659..114dab42 100644 --- a/plugins/main/ipvlan/ipvlan_test.go +++ b/plugins/main/ipvlan/ipvlan_test.go @@ -234,7 +234,7 @@ func ipvlanAddCheckDelTest(conf string, netName string, IFNAME string, originalN args.StdinData = confString - // CNI Check on macvlan in the target namespace + // CNI Check on ipvlan in the target namespace err = originalNS.Do(func(ns.NetNS) error { defer GinkgoRecover() @@ -465,4 +465,50 @@ var _ = Describe("ipvlan Operations", func() { ipvlanAddCheckDelTest(conf, "ipvlanTest2", IFNAME, originalNS) }) + + It("configures and deconfigures a ipvlan link with ADD/DEL, without master config", func() { + const IFNAME = "ipvl0" + conf := `{ + "cniVersion": "0.3.1", + "name": "mynet", + "type": "ipvlan", + "ipam": { + "type": "host-local", + "subnet": "10.1.2.0/24" + } +}` + + targetNs, err := testutils.NewNS() + Expect(err).NotTo(HaveOccurred()) + defer targetNs.Close() + + // 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()) + + ipvlanAddDelTest(conf, IFNAME, originalNS) + }) })