Skip to content

Commit

Permalink
Merge pull request #636 from EdDev/bridge-mac-specification
Browse files Browse the repository at this point in the history
bridge: Add mac field to specify container iface mac
  • Loading branch information
dcbw authored Jun 30, 2021
2 parents eddf2f2 + a3cde17 commit f14ff66
Show file tree
Hide file tree
Showing 5 changed files with 199 additions and 24 deletions.
21 changes: 14 additions & 7 deletions pkg/ip/link_linux.go
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ var (
ErrLinkNotFound = errors.New("link not found")
)

func makeVethPair(name, peer string, mtu int) (netlink.Link, error) {
func makeVethPair(name, peer string, mtu int, mac string) (netlink.Link, error) {
veth := &netlink.Veth{
LinkAttrs: netlink.LinkAttrs{
Name: name,
Expand All @@ -41,6 +41,13 @@ func makeVethPair(name, peer string, mtu int) (netlink.Link, error) {
},
PeerName: peer,
}
if mac != "" {
m, err := net.ParseMAC(mac)
if err != nil {
return nil, err
}
veth.LinkAttrs.HardwareAddr = m
}
if err := netlink.LinkAdd(veth); err != nil {
return nil, err
}
Expand All @@ -61,7 +68,7 @@ func peerExists(name string) bool {
return true
}

func makeVeth(name, vethPeerName string, mtu int) (peerName string, veth netlink.Link, err error) {
func makeVeth(name, vethPeerName string, mtu int, mac string) (peerName string, veth netlink.Link, err error) {
for i := 0; i < 10; i++ {
if vethPeerName != "" {
peerName = vethPeerName
Expand All @@ -72,7 +79,7 @@ func makeVeth(name, vethPeerName string, mtu int) (peerName string, veth netlink
}
}

veth, err = makeVethPair(name, peerName, mtu)
veth, err = makeVethPair(name, peerName, mtu, mac)
switch {
case err == nil:
return
Expand Down Expand Up @@ -131,8 +138,8 @@ func ifaceFromNetlinkLink(l netlink.Link) net.Interface {
// devices and move the host-side veth into the provided hostNS namespace.
// hostVethName: If hostVethName is not specified, the host-side veth name will use a random string.
// On success, SetupVethWithName returns (hostVeth, containerVeth, nil)
func SetupVethWithName(contVethName, hostVethName string, mtu int, hostNS ns.NetNS) (net.Interface, net.Interface, error) {
hostVethName, contVeth, err := makeVeth(contVethName, hostVethName, mtu)
func SetupVethWithName(contVethName, hostVethName string, mtu int, contVethMac string, hostNS ns.NetNS) (net.Interface, net.Interface, error) {
hostVethName, contVeth, err := makeVeth(contVethName, hostVethName, mtu, contVethMac)
if err != nil {
return net.Interface{}, net.Interface{}, err
}
Expand Down Expand Up @@ -174,8 +181,8 @@ func SetupVethWithName(contVethName, hostVethName string, mtu int, hostNS ns.Net
// Call SetupVeth from inside the container netns. It will create both veth
// devices and move the host-side veth into the provided hostNS namespace.
// On success, SetupVeth returns (hostVeth, containerVeth, nil)
func SetupVeth(contVethName string, mtu int, hostNS ns.NetNS) (net.Interface, net.Interface, error) {
return SetupVethWithName(contVethName, "", mtu, hostNS)
func SetupVeth(contVethName string, mtu int, contVethMac string, hostNS ns.NetNS) (net.Interface, net.Interface, error) {
return SetupVethWithName(contVethName, "", mtu, contVethMac, hostNS)
}

// DelLinkByName removes an interface link.
Expand Down
34 changes: 30 additions & 4 deletions pkg/ip/link_linux_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -70,7 +70,7 @@ var _ = Describe("Link", func() {
_ = containerNetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

hostVeth, containerVeth, err = ip.SetupVeth(fmt.Sprintf(ifaceFormatString, ifaceCounter), mtu, hostNetNS)
hostVeth, containerVeth, err = ip.SetupVeth(fmt.Sprintf(ifaceFormatString, ifaceCounter), mtu, "", hostNetNS)
if err != nil {
return err
}
Expand Down Expand Up @@ -157,7 +157,7 @@ var _ = Describe("Link", func() {
_ = containerNetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

_, _, err := ip.SetupVeth(containerVethName, mtu, hostNetNS)
_, _, err := ip.SetupVeth(containerVethName, mtu, "", hostNetNS)
Expect(err.Error()).To(Equal(fmt.Sprintf("container veth name provided (%s) already exists", containerVethName)))

return nil
Expand Down Expand Up @@ -187,7 +187,7 @@ var _ = Describe("Link", func() {
It("returns useful error", func() {
_ = containerNetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
_, _, err := ip.SetupVeth(containerVethName, mtu, hostNetNS)
_, _, err := ip.SetupVeth(containerVethName, mtu, "", hostNetNS)
Expect(err.Error()).To(HavePrefix("failed to move veth to host netns: "))

return nil
Expand All @@ -205,7 +205,7 @@ var _ = Describe("Link", func() {
_ = containerNetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

hostVeth, _, err := ip.SetupVeth(containerVethName, mtu, hostNetNS)
hostVeth, _, err := ip.SetupVeth(containerVethName, mtu, "", hostNetNS)
Expect(err).NotTo(HaveOccurred())
hostVethName = hostVeth.Name
return nil
Expand All @@ -231,6 +231,32 @@ var _ = Describe("Link", func() {
})
})

It("successfully creates a veth pair with an explicit mac", func() {
const mac = "02:00:00:00:01:23"
_ = containerNetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

hostVeth, _, err := ip.SetupVeth(containerVethName, mtu, mac, hostNetNS)
Expect(err).NotTo(HaveOccurred())
hostVethName = hostVeth.Name

link, err := netlink.LinkByName(containerVethName)
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().HardwareAddr.String()).To(Equal(mac))

return nil
})

_ = hostNetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

link, err := netlink.LinkByName(hostVethName)
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().HardwareAddr.String()).NotTo(Equal(mac))

return nil
})
})
})

It("DelLinkByName must delete the veth endpoints", func() {
Expand Down
55 changes: 47 additions & 8 deletions plugins/main/bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,25 @@ type NetConf struct {
HairpinMode bool `json:"hairpinMode"`
PromiscMode bool `json:"promiscMode"`
Vlan int `json:"vlan"`

Args struct {
Cni BridgeArgs `json:"cni,omitempty"`
} `json:"args,omitempty"`
RuntimeConfig struct {
Mac string `json:"mac,omitempty"`
} `json:"runtimeConfig,omitempty"`

mac string
}

type BridgeArgs struct {
Mac string `json:"mac,omitempty"`
}

// MacEnvArgs represents CNI_ARGS
type MacEnvArgs struct {
types.CommonArgs
MAC types.UnmarshallableString `json:"mac,omitempty"`
}

type gwInfo struct {
Expand All @@ -70,7 +89,7 @@ func init() {
runtime.LockOSThread()
}

func loadNetConf(bytes []byte) (*NetConf, string, error) {
func loadNetConf(bytes []byte, envArgs string) (*NetConf, string, error) {
n := &NetConf{
BrName: defaultBrName,
}
Expand All @@ -80,6 +99,26 @@ func loadNetConf(bytes []byte) (*NetConf, string, error) {
if n.Vlan < 0 || n.Vlan > 4094 {
return nil, "", fmt.Errorf("invalid VLAN ID %d (must be between 0 and 4094)", n.Vlan)
}

if envArgs != "" {
e := MacEnvArgs{}
if err := types.LoadArgs(envArgs, &e); err != nil {
return nil, "", err
}

if e.MAC != "" {
n.mac = string(e.MAC)
}
}

if mac := n.Args.Cni.Mac; mac != "" {
n.mac = mac
}

if mac := n.RuntimeConfig.Mac; mac != "" {
n.mac = mac
}

return n, n.CNIVersion, nil
}

Expand Down Expand Up @@ -273,7 +312,7 @@ func ensureVlanInterface(br *netlink.Bridge, vlanId int) (netlink.Link, error) {
return nil, fmt.Errorf("faild to find host namespace: %v", err)
}

_, brGatewayIface, err := setupVeth(hostNS, br, name, br.MTU, false, vlanId)
_, brGatewayIface, err := setupVeth(hostNS, br, name, br.MTU, false, vlanId, "")
if err != nil {
return nil, fmt.Errorf("faild to create vlan gateway %q: %v", name, err)
}
Expand All @@ -287,13 +326,13 @@ func ensureVlanInterface(br *netlink.Bridge, vlanId int) (netlink.Link, error) {
return brGatewayVeth, nil
}

func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairpinMode bool, vlanID int) (*current.Interface, *current.Interface, error) {
func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairpinMode bool, vlanID int, mac string) (*current.Interface, *current.Interface, error) {
contIface := &current.Interface{}
hostIface := &current.Interface{}

err := netns.Do(func(hostNS ns.NetNS) error {
// create the veth pair in the container and move host end into host netns
hostVeth, containerVeth, err := ip.SetupVeth(ifName, mtu, hostNS)
hostVeth, containerVeth, err := ip.SetupVeth(ifName, mtu, mac, hostNS)
if err != nil {
return err
}
Expand Down Expand Up @@ -380,7 +419,7 @@ func enableIPForward(family int) error {
func cmdAdd(args *skel.CmdArgs) error {
var success bool = false

n, cniVersion, err := loadNetConf(args.StdinData)
n, cniVersion, err := loadNetConf(args.StdinData, args.Args)
if err != nil {
return err
}
Expand All @@ -406,7 +445,7 @@ func cmdAdd(args *skel.CmdArgs) error {
}
defer netns.Close()

hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode, n.Vlan)
hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode, n.Vlan, n.mac)
if err != nil {
return err
}
Expand Down Expand Up @@ -585,7 +624,7 @@ func cmdAdd(args *skel.CmdArgs) error {
}

func cmdDel(args *skel.CmdArgs) error {
n, _, err := loadNetConf(args.StdinData)
n, _, err := loadNetConf(args.StdinData, args.Args)
if err != nil {
return err
}
Expand Down Expand Up @@ -776,7 +815,7 @@ func validateCniContainerInterface(intf current.Interface) (cniBridgeIf, error)

func cmdCheck(args *skel.CmdArgs) error {

n, _, err := loadNetConf(args.StdinData)
n, _, err := loadNetConf(args.StdinData, args.Args)
if err != nil {
return err
}
Expand Down
Loading

0 comments on commit f14ff66

Please sign in to comment.