From bb2d255a72273e4652503cfd8e38597ee5c29e94 Mon Sep 17 00:00:00 2001 From: Christopher Dziomba Date: Fri, 15 Nov 2024 13:17:54 +0100 Subject: [PATCH] Add EUI on IPv6 L2VNIs for IPv6 ND --- pkg/nl/create.go | 28 +++++++++++++++------------- pkg/nl/layer2.go | 33 ++++++++++++++++++++++++++++++--- pkg/nl/layer3.go | 2 +- 3 files changed, 46 insertions(+), 17 deletions(-) diff --git a/pkg/nl/create.go b/pkg/nl/create.go index f427d6c2..33617d0d 100644 --- a/pkg/nl/create.go +++ b/pkg/nl/create.go @@ -26,7 +26,7 @@ func (n *Manager) createVRF(vrfName string, table int) (*netlink.Vrf, error) { if err := n.toolkit.LinkAdd(&netlinkVrf); err != nil { return nil, fmt.Errorf("error adding link: %w", err) } - if err := n.disableEUIAutogeneration(vrfName); err != nil { + if err := n.setEUIAutogeneration(vrfName, false); err != nil { return nil, err } if err := n.toolkit.LinkSetUp(&netlinkVrf); err != nil { @@ -36,7 +36,7 @@ func (n *Manager) createVRF(vrfName string, table int) (*netlink.Vrf, error) { return &netlinkVrf, nil } -func (n *Manager) createBridge(bridgeName string, macAddress *net.HardwareAddr, masterIdx, mtu int, underlayRMAC bool) (*netlink.Bridge, error) { +func (n *Manager) createBridge(bridgeName string, macAddress *net.HardwareAddr, masterIdx, mtu int, underlayRMAC, assignEUI bool) (*netlink.Bridge, error) { netlinkBridge := netlink.Bridge{ LinkAttrs: netlink.LinkAttrs{ Name: bridgeName, @@ -64,7 +64,7 @@ func (n *Manager) createBridge(bridgeName string, macAddress *net.HardwareAddr, if err := n.toolkit.LinkAdd(&netlinkBridge); err != nil { return nil, fmt.Errorf("error adding link: %w", err) } - if err := n.disableEUIAutogeneration(bridgeName); err != nil { + if err := n.setEUIAutogeneration(bridgeName, assignEUI); err != nil { return nil, fmt.Errorf("error disabling EUI autogeneration: %w", err) } @@ -109,21 +109,25 @@ func (n *Manager) createVXLAN(vxlanName string, bridgeIdx, vni, mtu int, hairpin return nil, fmt.Errorf("error setting link's hairpin mode: %w", err) } } - if err := n.disableEUIAutogeneration(vxlanName); err != nil { + if err := n.setEUIAutogeneration(vxlanName, false); err != nil { return nil, err } return &netlinkVXLAN, nil } -func (*Manager) disableEUIAutogeneration(intfName string) error { +func (*Manager) setEUIAutogeneration(intfName string, generateEUI bool) error { fileName := fmt.Sprintf("%s/ipv6/conf/%s/addr_gen_mode", procSysNetPath, intfName) file, err := os.OpenFile(fileName, os.O_WRONLY, 0) if err != nil { return fmt.Errorf("error opening file: %w", err) } defer file.Close() - if _, err := file.WriteString("1\n"); err != nil { + value := "1" + if generateEUI { + value = "0" + } + if _, err := fmt.Fprintf(file, "%s\n", value); err != nil { return fmt.Errorf("error writing to file: %w", err) } return nil @@ -142,13 +146,11 @@ func (n *Manager) createLink(vethName, peerName string, masterIdx, mtu int, gene return nil, fmt.Errorf("error adding link: %w", err) } - if !generateEUI { - if err := n.disableEUIAutogeneration(vethName); err != nil { - return nil, err - } - if err := n.disableEUIAutogeneration(peerName); err != nil { - return nil, err - } + if err := n.setEUIAutogeneration(vethName, generateEUI); err != nil { + return nil, err + } + if err := n.setEUIAutogeneration(peerName, generateEUI); err != nil { + return nil, err } return &netlinkVeth, nil diff --git a/pkg/nl/layer2.go b/pkg/nl/layer2.go index c149bda9..40d61b95 100644 --- a/pkg/nl/layer2.go +++ b/pkg/nl/layer2.go @@ -130,7 +130,7 @@ func (n *Manager) CreateL2(info *Layer2Information) error { } func (n *Manager) setupBridge(info *Layer2Information, masterIdx int) (*netlink.Bridge, error) { - bridge, err := n.createBridge(fmt.Sprintf("%s%d", layer2Prefix, info.VlanID), info.AnycastMAC, masterIdx, info.MTU, false) + bridge, err := n.createBridge(fmt.Sprintf("%s%d", layer2Prefix, info.VlanID), info.AnycastMAC, masterIdx, info.MTU, false, len(info.AnycastGateways) > 0) if err != nil { return nil, err } @@ -247,7 +247,29 @@ func (n *Manager) reconcileIPAddresses(intf netlink.Link, current, desired []*ne return nil } +func (n *Manager) reconcileEUIAutogeneration(intfName string, intf netlink.Link, desired []*netlink.Addr) error { + enableEUI := len(desired) > 0 + if err := n.setEUIAutogeneration(intfName, enableEUI); err != nil { + return fmt.Errorf("error setting EUI autogeneration: %w", err) + } + if !enableEUI { + addresses, err := n.toolkit.AddrList(intf, unix.AF_INET6) + if err != nil { + return fmt.Errorf("error listing link's IPv6 addresses: %w", err) + } + for i := range addresses { + if addresses[i].IP.IsLinkLocalUnicast() { + if err := n.toolkit.AddrDel(intf, &addresses[i]); err != nil { + return fmt.Errorf("error removing link local IPv6 address: %w", err) + } + } + } + } + return nil +} + func (n *Manager) ReconcileL2(current, desired *Layer2Information) error { + bridgeName := fmt.Sprintf("%s%d", layer2Prefix, current.VlanID) if len(desired.AnycastGateways) > 0 && desired.AnycastMAC == nil { return fmt.Errorf("anycastGateways require anycastMAC to be set") } @@ -282,7 +304,7 @@ func (n *Manager) ReconcileL2(current, desired *Layer2Information) error { return err } - if err := n.configureBridge(fmt.Sprintf("%s%d", layer2Prefix, current.VlanID)); err != nil { + if err := n.configureBridge(bridgeName); err != nil { return err } @@ -291,7 +313,12 @@ func (n *Manager) ReconcileL2(current, desired *Layer2Information) error { } // Add/Remove anycast gateways - return n.reconcileIPAddresses(current.bridge, current.AnycastGateways, desired.AnycastGateways) + if err := n.reconcileIPAddresses(current.bridge, current.AnycastGateways, desired.AnycastGateways); err != nil { + return err + } + + // Reconcile EUI Autogeneration + return n.reconcileEUIAutogeneration(bridgeName, current.bridge, desired.AnycastGateways) } func (n *Manager) setMTU(current, desired *Layer2Information) error { diff --git a/pkg/nl/layer3.go b/pkg/nl/layer3.go index 1c8f4ed6..37ae9edf 100644 --- a/pkg/nl/layer3.go +++ b/pkg/nl/layer3.go @@ -39,7 +39,7 @@ func (n *Manager) CreateL3(info VRFInformation) error { return err } - bridge, err := n.createBridge(bridgePrefix+info.Name, nil, vrf.Attrs().Index, defaultMtu, true) + bridge, err := n.createBridge(bridgePrefix+info.Name, nil, vrf.Attrs().Index, defaultMtu, true, false) if err != nil { return err }