Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add dual stack support #1446

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 5 additions & 3 deletions backend/common.go
Original file line number Diff line number Diff line change
Expand Up @@ -24,9 +24,11 @@ import (
)

type ExternalInterface struct {
Iface *net.Interface
IfaceAddr net.IP
ExtAddr net.IP
Iface *net.Interface
IfaceAddr net.IP
IfaceV6Addr net.IP
ExtAddr net.IP
ExtV6Addr net.IP
}

// Besides the entry points in the Backend interface, the backend's New()
Expand Down
58 changes: 58 additions & 0 deletions backend/vxlan/device.go
Original file line number Diff line number Diff line change
Expand Up @@ -124,13 +124,26 @@ func (dev *vxlanDevice) Configure(ipa ip.IP4Net, flannelnet ip.IP4Net) error {
return nil
}

func (dev *vxlanDevice) ConfigureIPv6(ipn ip.IP6Net, flannelnet ip.IP6Net) error {
if err := ip.EnsureV6AddressOnLink(ipn, flannelnet, dev.link); err != nil {
return fmt.Errorf("failed to ensure v6 address of interface %s: %s", dev.link.Attrs().Name, err)
}

if err := netlink.LinkSetUp(dev.link); err != nil {
return fmt.Errorf("failed to set v6 interface %s to UP state: %s", dev.link.Attrs().Name, err)
}

return nil
}

func (dev *vxlanDevice) MACAddr() net.HardwareAddr {
return dev.link.HardwareAddr
}

type neighbor struct {
MAC net.HardwareAddr
IP ip.IP4
IP6 *ip.IP6
}

func (dev *vxlanDevice) AddFDB(n neighbor) error {
Expand All @@ -145,6 +158,18 @@ func (dev *vxlanDevice) AddFDB(n neighbor) error {
})
}

func (dev *vxlanDevice) AddV6FDB(n neighbor) error {
log.V(4).Infof("calling AddV6FDB: %v, %v", n.IP6, n.MAC)
return netlink.NeighSet(&netlink.Neigh{
LinkIndex: dev.link.Index,
State: netlink.NUD_PERMANENT,
Family: syscall.AF_BRIDGE,
Flags: netlink.NTF_SELF,
IP: n.IP6.ToIP(),
HardwareAddr: n.MAC,
})
}

func (dev *vxlanDevice) DelFDB(n neighbor) error {
log.V(4).Infof("calling DelFDB: %v, %v", n.IP, n.MAC)
return netlink.NeighDel(&netlink.Neigh{
Expand All @@ -156,6 +181,17 @@ func (dev *vxlanDevice) DelFDB(n neighbor) error {
})
}

func (dev *vxlanDevice) DelV6FDB(n neighbor) error {
log.V(4).Infof("calling DelV6FDB: %v, %v", n.IP6, n.MAC)
return netlink.NeighDel(&netlink.Neigh{
LinkIndex: dev.link.Index,
Family: syscall.AF_BRIDGE,
Flags: netlink.NTF_SELF,
IP: n.IP6.ToIP(),
HardwareAddr: n.MAC,
})
}

func (dev *vxlanDevice) AddARP(n neighbor) error {
log.V(4).Infof("calling AddARP: %v, %v", n.IP, n.MAC)
return netlink.NeighSet(&netlink.Neigh{
Expand All @@ -167,6 +203,17 @@ func (dev *vxlanDevice) AddARP(n neighbor) error {
})
}

func (dev *vxlanDevice) AddV6ARP(n neighbor) error {
log.V(4).Infof("calling AddV6ARP: %v, %v", n.IP6, n.MAC)
return netlink.NeighSet(&netlink.Neigh{
LinkIndex: dev.link.Index,
State: netlink.NUD_PERMANENT,
Type: syscall.RTN_UNICAST,
IP: n.IP6.ToIP(),
HardwareAddr: n.MAC,
})
}

func (dev *vxlanDevice) DelARP(n neighbor) error {
log.V(4).Infof("calling DelARP: %v, %v", n.IP, n.MAC)
return netlink.NeighDel(&netlink.Neigh{
Expand All @@ -178,6 +225,17 @@ func (dev *vxlanDevice) DelARP(n neighbor) error {
})
}

func (dev *vxlanDevice) DelV6ARP(n neighbor) error {
log.V(4).Infof("calling DelV6ARP: %v, %v", n.IP6, n.MAC)
return netlink.NeighDel(&netlink.Neigh{
LinkIndex: dev.link.Index,
State: netlink.NUD_PERMANENT,
Type: syscall.RTN_UNICAST,
IP: n.IP6.ToIP(),
HardwareAddr: n.MAC,
})
}

func vxlanLinksIncompat(l1, l2 netlink.Link) string {
if l1.Type() != l2.Type() {
return fmt.Sprintf("link type: %v vs %v", l1.Type(), l2.Type())
Expand Down
99 changes: 70 additions & 29 deletions backend/vxlan/vxlan.go
Original file line number Diff line number Diff line change
Expand Up @@ -88,19 +88,34 @@ func New(sm subnet.Manager, extIface *backend.ExternalInterface) (backend.Backen
return backend, nil
}

func newSubnetAttrs(publicIP net.IP, vnid uint16, mac net.HardwareAddr) (*subnet.LeaseAttrs, error) {
data, err := json.Marshal(&vxlanLeaseAttrs{
VNI: vnid,
VtepMAC: hardwareAddr(mac)})
if err != nil {
return nil, err
func newSubnetAttrs(publicIP net.IP, publicIPv6 net.IP, vnid uint16, dev, v6Dev *vxlanDevice) (*subnet.LeaseAttrs, error) {
leaseAttrs := &subnet.LeaseAttrs{
BackendType: "vxlan",
}
if publicIP != nil && dev != nil {
data, err := json.Marshal(&vxlanLeaseAttrs{
VNI: vnid,
VtepMAC: hardwareAddr(dev.MACAddr()),
})
if err != nil {
return nil, err
}
leaseAttrs.PublicIP = ip.FromIP(publicIP)
leaseAttrs.BackendData = json.RawMessage(data)
}

return &subnet.LeaseAttrs{
PublicIP: ip.FromIP(publicIP),
BackendType: "vxlan",
BackendData: json.RawMessage(data),
}, nil
if publicIPv6 != nil && v6Dev != nil {
data, err := json.Marshal(&vxlanLeaseAttrs{
VNI: vnid,
VtepMAC: hardwareAddr(v6Dev.MACAddr()),
})
if err != nil {
return nil, err
}
leaseAttrs.PublicIPv6 = ip.FromIP6(publicIPv6)
leaseAttrs.BackendV6Data = json.RawMessage(data)
}
return leaseAttrs, nil
}

func (be *VXLANBackend) RegisterNetwork(ctx context.Context, wg *sync.WaitGroup, config *subnet.Config) (backend.Network, error) {
Expand All @@ -122,23 +137,43 @@ func (be *VXLANBackend) RegisterNetwork(ctx context.Context, wg *sync.WaitGroup,
}
log.Infof("VXLAN config: VNI=%d Port=%d GBP=%v Learning=%v DirectRouting=%v", cfg.VNI, cfg.Port, cfg.GBP, cfg.Learning, cfg.DirectRouting)

devAttrs := vxlanDeviceAttrs{
vni: uint32(cfg.VNI),
name: fmt.Sprintf("flannel.%v", cfg.VNI),
vtepIndex: be.extIface.Iface.Index,
vtepAddr: be.extIface.IfaceAddr,
vtepPort: cfg.Port,
gbp: cfg.GBP,
learning: cfg.Learning,
}
var dev, v6Dev *vxlanDevice
var err error
if config.EnableIPv4 {
devAttrs := vxlanDeviceAttrs{
vni: uint32(cfg.VNI),
name: fmt.Sprintf("flannel.%v", cfg.VNI),
vtepIndex: be.extIface.Iface.Index,
vtepAddr: be.extIface.IfaceAddr,
vtepPort: cfg.Port,
gbp: cfg.GBP,
learning: cfg.Learning,
}

dev, err := newVXLANDevice(&devAttrs)
if err != nil {
return nil, err
dev, err = newVXLANDevice(&devAttrs)
if err != nil {
return nil, err
}
dev.directRouting = cfg.DirectRouting
}
if config.EnableIPv6 {
v6DevAttrs := vxlanDeviceAttrs{
vni: uint32(cfg.VNI),
name: fmt.Sprintf("flannel-v6.%v", cfg.VNI),
vtepIndex: be.extIface.Iface.Index,
vtepAddr: be.extIface.IfaceV6Addr,
vtepPort: cfg.Port,
gbp: cfg.GBP,
learning: cfg.Learning,
}
v6Dev, err = newVXLANDevice(&v6DevAttrs)
if err != nil {
return nil, err
}
v6Dev.directRouting = cfg.DirectRouting
}
dev.directRouting = cfg.DirectRouting

subnetAttrs, err := newSubnetAttrs(be.extIface.ExtAddr, uint16(cfg.VNI), dev.MACAddr())
subnetAttrs, err := newSubnetAttrs(be.extIface.ExtAddr, be.extIface.ExtV6Addr, uint16(cfg.VNI), dev, v6Dev)
if err != nil {
return nil, err
}
Expand All @@ -155,11 +190,17 @@ func (be *VXLANBackend) RegisterNetwork(ctx context.Context, wg *sync.WaitGroup,
// Ensure that the device has a /32 address so that no broadcast routes are created.
// This IP is just used as a source address for host to workload traffic (so
// the return path for the traffic has an address on the flannel network to use as the destination)
if err := dev.Configure(ip.IP4Net{IP: lease.Subnet.IP, PrefixLen: 32}, config.Network); err != nil {
return nil, fmt.Errorf("failed to configure interface %s: %s", dev.link.Attrs().Name, err)
if config.EnableIPv4 {
if err := dev.Configure(ip.IP4Net{IP: lease.Subnet.IP, PrefixLen: 32}, config.Network); err != nil {
return nil, fmt.Errorf("failed to configure interface %s: %s", dev.link.Attrs().Name, err)
}
}

return newNetwork(be.subnetMgr, be.extIface, dev, ip.IP4Net{}, lease)
if config.EnableIPv6 {
if err := v6Dev.ConfigureIPv6(ip.IP6Net{IP: lease.IPv6Subnet.IP, PrefixLen: 128}, config.Network); err != nil {
return nil, fmt.Errorf("failed to configure interface %s: %s", v6Dev.link.Attrs().Name, err)
}
}
return newNetwork(be.subnetMgr, be.extIface, dev, v6Dev, ip.IP4Net{}, lease)
}

// So we can make it JSON (un)marshalable
Expand Down
Loading