@@ -11,32 +11,34 @@ import (
1111 "github.com/vishvananda/netlink"
1212)
1313
14- // EnsureVXLAN creates or reconciles the VXLAN interface for the given network.
15- // vni is the VXLAN Network Identifier, ifaceName is the interface name to use,
16- // and nodeIP is the local node's IP for VTEP termination.
17- // Idempotent: no-ops if the interface already exists with matching configuration.
18- func (m * LinuxNetManager ) EnsureVXLAN (_ context.Context , vni uint32 , ifaceName , nodeIP string ) error {
14+ // EnsureVXLAN creates or reconciles the VXLAN interface for the given network,
15+ // attaches it to bridgeName, and brings it up. bridgeName must already exist
16+ // (call EnsureNetwork first). Idempotent.
17+ func (m * LinuxNetManager ) EnsureVXLAN (_ context.Context , vni uint32 , ifaceName , nodeIP , bridgeName string ) error {
1918 localIP := net .ParseIP (nodeIP )
2019 if localIP == nil {
2120 return fmt .Errorf ("invalid nodeIP %q" , nodeIP )
2221 }
2322
2423 link , err := netlink .LinkByName (ifaceName )
2524 if err == nil {
26- // Interface already exists — ensure it is up.
27- return netlink .LinkSetUp (link )
25+ // Interface already exists — ensure it is up and attached to bridge.
26+ if err := netlink .LinkSetUp (link ); err != nil {
27+ return err
28+ }
29+ return m .attachToBridge (link , bridgeName )
2830 }
2931
3032 vx := & netlink.Vxlan {
3133 LinkAttrs : netlink.LinkAttrs {
3234 Name : ifaceName ,
3335 },
34- VxlanId : int (vni ),
35- SrcAddr : localIP .To4 (),
36- Port : 8472 ,
37- Learning : false ,
38- L2miss : false ,
39- L3miss : false ,
36+ VxlanId : int (vni ),
37+ SrcAddr : localIP .To4 (),
38+ Port : 8472 ,
39+ Learning : false ,
40+ L2miss : false ,
41+ L3miss : false ,
4042 }
4143 if err := netlink .LinkAdd (vx ); err != nil {
4244 return fmt .Errorf ("create vxlan %s (vni %d): %w" , ifaceName , vni , err )
@@ -46,7 +48,27 @@ func (m *LinuxNetManager) EnsureVXLAN(_ context.Context, vni uint32, ifaceName,
4648 if err != nil {
4749 return fmt .Errorf ("fetch vxlan %s after create: %w" , ifaceName , err )
4850 }
49- return netlink .LinkSetUp (link )
51+ if err := netlink .LinkSetUp (link ); err != nil {
52+ return err
53+ }
54+ return m .attachToBridge (link , bridgeName )
55+ }
56+
57+ // attachToBridge attaches link to the bridge named bridgeName.
58+ // No-op if link is already a member of that bridge or bridgeName is empty.
59+ func (m * LinuxNetManager ) attachToBridge (link netlink.Link , bridgeName string ) error {
60+ if bridgeName == "" {
61+ return nil
62+ }
63+ bridge , err := netlink .LinkByName (bridgeName )
64+ if err != nil {
65+ return fmt .Errorf ("get bridge %s: %w" , bridgeName , err )
66+ }
67+ // Already a member?
68+ if link .Attrs ().MasterIndex == bridge .Attrs ().Index {
69+ return nil
70+ }
71+ return netlink .LinkSetMaster (link , bridge )
5072}
5173
5274// SyncFDB reconciles the local FDB (forwarding database) on the VXLAN interface
0 commit comments