Merge pull request #534 from s1061123/dev/add-default-ipvlan

ipvlan: make master config as optional
This commit is contained in:
Bryan Boreham 2020-10-07 16:29:56 +01:00 committed by GitHub
commit e1517e2498
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 78 additions and 7 deletions

View File

@ -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.

View File

@ -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 {

View File

@ -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)
})
})