Merge pull request #480 from clinta/macvlan-mac

macvlan: set mac address from args
This commit is contained in:
Casey Callendrello 2020-05-27 17:33:30 +02:00 committed by GitHub
commit 67175607ad
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 220 additions and 11 deletions

View File

@ -45,6 +45,17 @@ type NetConf struct {
Master string `json:"master"` Master string `json:"master"`
Mode string `json:"mode"` Mode string `json:"mode"`
MTU int `json:"mtu"` MTU int `json:"mtu"`
Mac string `json:"mac,omitempty"`
RuntimeConfig struct {
Mac string `json:"mac,omitempty"`
} `json:"runtimeConfig,omitempty"`
}
// MacEnvArgs represents CNI_ARG
type MacEnvArgs struct {
types.CommonArgs
MAC types.UnmarshallableString `json:"mac,omitempty"`
} }
func init() { func init() {
@ -73,7 +84,7 @@ func getDefaultRouteInterfaceName() (string, error) {
return "", fmt.Errorf("no default route interface found") return "", fmt.Errorf("no default route interface found")
} }
func loadConf(bytes []byte) (*NetConf, string, error) { func loadConf(bytes []byte, envArgs string) (*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)
@ -95,6 +106,22 @@ func loadConf(bytes []byte) (*NetConf, string, error) {
return nil, "", fmt.Errorf("invalid MTU %d, must be [0, master MTU(%d)]", n.MTU, masterMTU) return nil, "", fmt.Errorf("invalid MTU %d, must be [0, master MTU(%d)]", n.MTU, masterMTU)
} }
if envArgs != "" {
e := MacEnvArgs{}
err := types.LoadArgs(envArgs, &e)
if err != nil {
return nil, "", err
}
if e.MAC != "" {
n.Mac = string(e.MAC)
}
}
if n.RuntimeConfig.Mac != "" {
n.Mac = n.RuntimeConfig.Mac
}
return n, n.CNIVersion, nil return n, n.CNIVersion, nil
} }
@ -156,14 +183,24 @@ func createMacvlan(conf *NetConf, ifName string, netns ns.NetNS) (*current.Inter
return nil, err return nil, err
} }
linkAttrs := netlink.LinkAttrs{
MTU: conf.MTU,
Name: tmpName,
ParentIndex: m.Attrs().Index,
Namespace: netlink.NsFd(int(netns.Fd())),
}
if conf.Mac != "" {
addr, err := net.ParseMAC(conf.Mac)
if err != nil {
return nil, fmt.Errorf("invalid args %v for MAC addr: %v", conf.Mac, err)
}
linkAttrs.HardwareAddr = addr
}
mv := &netlink.Macvlan{ mv := &netlink.Macvlan{
LinkAttrs: netlink.LinkAttrs{ LinkAttrs: linkAttrs,
MTU: conf.MTU, Mode: mode,
Name: tmpName,
ParentIndex: m.Attrs().Index,
Namespace: netlink.NsFd(int(netns.Fd())),
},
Mode: mode,
} }
if err := netlink.LinkAdd(mv); err != nil { if err := netlink.LinkAdd(mv); err != nil {
@ -204,7 +241,7 @@ func createMacvlan(conf *NetConf, ifName string, netns ns.NetNS) (*current.Inter
} }
func cmdAdd(args *skel.CmdArgs) error { func cmdAdd(args *skel.CmdArgs) error {
n, cniVersion, err := loadConf(args.StdinData) n, cniVersion, err := loadConf(args.StdinData, args.Args)
if err != nil { if err != nil {
return err return err
} }
@ -311,7 +348,7 @@ func cmdAdd(args *skel.CmdArgs) error {
} }
func cmdDel(args *skel.CmdArgs) error { func cmdDel(args *skel.CmdArgs) error {
n, _, err := loadConf(args.StdinData) n, _, err := loadConf(args.StdinData, args.Args)
if err != nil { if err != nil {
return err return err
} }
@ -349,7 +386,7 @@ func main() {
func cmdCheck(args *skel.CmdArgs) error { func cmdCheck(args *skel.CmdArgs) error {
n, _, err := loadConf(args.StdinData) n, _, err := loadConf(args.StdinData, args.Args)
if err != nil { if err != nil {
return err return err
} }

View File

@ -594,4 +594,176 @@ var _ = Describe("macvlan Operations", func() {
Expect(err).NotTo(HaveOccurred()) Expect(err).NotTo(HaveOccurred())
}) })
It("configures and deconfigures l2 macvlan link with mac address (from CNI_ARGS) with CNI v4 ADD/DEL", func() {
const IFNAME = "macvl0"
conf := fmt.Sprintf(`{
"cniVersion": "0.3.1",
"name": "mynet",
"type": "macvlan",
"master": "%s",
"ipam": {}
}`, MASTER_NAME)
targetNs, err := testutils.NewNS()
Expect(err).NotTo(HaveOccurred())
defer targetNs.Close()
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNs.Path(),
IfName: IFNAME,
StdinData: []byte(conf),
Args: "IgnoreUnknown=true;MAC=c2:11:22:33:44:55",
}
var result *current.Result
err = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
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(0))
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("c2:11:22:33:44:55")
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(0))
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())
})
It("configures and deconfigures l2 macvlan link with mac address (from RuntimeConfig) with ADD/DEL", func() {
const IFNAME = "macvl0"
conf := fmt.Sprintf(`{
"cniVersion": "0.3.1",
"capabilities": {"mac": true},
"RuntimeConfig": {
"mac": "c2:11:22:33:44:55"
},
"name": "mynet",
"type": "macvlan",
"master": "%s",
"ipam": {}
}`, MASTER_NAME)
targetNs, err := testutils.NewNS()
Expect(err).NotTo(HaveOccurred())
defer targetNs.Close()
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNs.Path(),
IfName: IFNAME,
StdinData: []byte(conf),
}
var result *current.Result
err = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
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(0))
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("c2:11:22:33:44:55")
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(0))
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())
})
}) })