2019-01-12 04:58:27 +00:00
|
|
|
// +build !windows
|
|
|
|
|
|
|
|
// Copyright 2015 flannel authors
|
|
|
|
//
|
|
|
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
|
|
|
// you may not use this file except in compliance with the License.
|
|
|
|
// You may obtain a copy of the License at
|
|
|
|
//
|
|
|
|
// http://www.apache.org/licenses/LICENSE-2.0
|
|
|
|
//
|
|
|
|
// Unless required by applicable law or agreed to in writing, software
|
|
|
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
|
|
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
|
|
// See the License for the specific language governing permissions and
|
|
|
|
// limitations under the License.
|
|
|
|
// +build !windows
|
|
|
|
|
|
|
|
package vxlan
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"net"
|
|
|
|
"syscall"
|
|
|
|
|
2021-03-18 22:40:29 +00:00
|
|
|
"github.com/containernetworking/plugins/pkg/utils/sysctl"
|
|
|
|
"github.com/flannel-io/flannel/pkg/ip"
|
2019-01-12 04:58:27 +00:00
|
|
|
"github.com/vishvananda/netlink"
|
2021-03-18 22:40:29 +00:00
|
|
|
log "k8s.io/klog"
|
2019-01-12 04:58:27 +00:00
|
|
|
)
|
|
|
|
|
|
|
|
type vxlanDeviceAttrs struct {
|
|
|
|
vni uint32
|
|
|
|
name string
|
|
|
|
vtepIndex int
|
|
|
|
vtepAddr net.IP
|
|
|
|
vtepPort int
|
|
|
|
gbp bool
|
2019-09-06 18:20:31 +00:00
|
|
|
learning bool
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
type vxlanDevice struct {
|
|
|
|
link *netlink.Vxlan
|
|
|
|
directRouting bool
|
|
|
|
}
|
|
|
|
|
|
|
|
func newVXLANDevice(devAttrs *vxlanDeviceAttrs) (*vxlanDevice, error) {
|
|
|
|
link := &netlink.Vxlan{
|
|
|
|
LinkAttrs: netlink.LinkAttrs{
|
|
|
|
Name: devAttrs.name,
|
|
|
|
},
|
|
|
|
VxlanId: int(devAttrs.vni),
|
|
|
|
VtepDevIndex: devAttrs.vtepIndex,
|
|
|
|
SrcAddr: devAttrs.vtepAddr,
|
|
|
|
Port: devAttrs.vtepPort,
|
2019-09-06 18:20:31 +00:00
|
|
|
Learning: devAttrs.learning,
|
2019-01-12 04:58:27 +00:00
|
|
|
GBP: devAttrs.gbp,
|
|
|
|
}
|
|
|
|
|
|
|
|
link, err := ensureLink(link)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
2021-03-18 22:40:29 +00:00
|
|
|
|
|
|
|
_, _ = sysctl.Sysctl(fmt.Sprintf("net/ipv6/conf/%s/accept_ra", devAttrs.name), "0")
|
|
|
|
|
2019-01-12 04:58:27 +00:00
|
|
|
return &vxlanDevice{
|
|
|
|
link: link,
|
|
|
|
}, nil
|
|
|
|
}
|
|
|
|
|
|
|
|
func ensureLink(vxlan *netlink.Vxlan) (*netlink.Vxlan, error) {
|
|
|
|
err := netlink.LinkAdd(vxlan)
|
|
|
|
if err == syscall.EEXIST {
|
|
|
|
// it's ok if the device already exists as long as config is similar
|
|
|
|
log.V(1).Infof("VXLAN device already exists")
|
|
|
|
existing, err := netlink.LinkByName(vxlan.Name)
|
|
|
|
if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
incompat := vxlanLinksIncompat(vxlan, existing)
|
|
|
|
if incompat == "" {
|
|
|
|
log.V(1).Infof("Returning existing device")
|
|
|
|
return existing.(*netlink.Vxlan), nil
|
|
|
|
}
|
|
|
|
|
|
|
|
// delete existing
|
|
|
|
log.Warningf("%q already exists with incompatable configuration: %v; recreating device", vxlan.Name, incompat)
|
|
|
|
if err = netlink.LinkDel(existing); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to delete interface: %v", err)
|
|
|
|
}
|
|
|
|
|
|
|
|
// create new
|
|
|
|
if err = netlink.LinkAdd(vxlan); err != nil {
|
|
|
|
return nil, fmt.Errorf("failed to create vxlan interface: %v", err)
|
|
|
|
}
|
|
|
|
} else if err != nil {
|
|
|
|
return nil, err
|
|
|
|
}
|
|
|
|
|
|
|
|
ifindex := vxlan.Index
|
|
|
|
link, err := netlink.LinkByIndex(vxlan.Index)
|
|
|
|
if err != nil {
|
|
|
|
return nil, fmt.Errorf("can't locate created vxlan device with index %v", ifindex)
|
|
|
|
}
|
|
|
|
|
|
|
|
var ok bool
|
|
|
|
if vxlan, ok = link.(*netlink.Vxlan); !ok {
|
|
|
|
return nil, fmt.Errorf("created vxlan device with index %v is not vxlan", ifindex)
|
|
|
|
}
|
|
|
|
|
|
|
|
return vxlan, nil
|
|
|
|
}
|
|
|
|
|
2021-03-18 22:40:29 +00:00
|
|
|
func (dev *vxlanDevice) Configure(ipa ip.IP4Net, flannelnet ip.IP4Net) error {
|
|
|
|
if err := ip.EnsureV4AddressOnLink(ipa, flannelnet, dev.link); err != nil {
|
2019-01-12 04:58:27 +00:00
|
|
|
return fmt.Errorf("failed to ensure address of interface %s: %s", dev.link.Attrs().Name, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
if err := netlink.LinkSetUp(dev.link); err != nil {
|
|
|
|
return fmt.Errorf("failed to set interface %s to UP state: %s", dev.link.Attrs().Name, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2021-08-17 09:27:54 +00:00
|
|
|
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: %w", 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: %w", dev.link.Attrs().Name, err)
|
|
|
|
}
|
|
|
|
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
|
2019-01-12 04:58:27 +00:00
|
|
|
func (dev *vxlanDevice) MACAddr() net.HardwareAddr {
|
|
|
|
return dev.link.HardwareAddr
|
|
|
|
}
|
|
|
|
|
|
|
|
type neighbor struct {
|
|
|
|
MAC net.HardwareAddr
|
|
|
|
IP ip.IP4
|
2021-08-17 09:27:54 +00:00
|
|
|
IP6 *ip.IP6
|
2019-01-12 04:58:27 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
func (dev *vxlanDevice) AddFDB(n neighbor) error {
|
|
|
|
log.V(4).Infof("calling AddFDB: %v, %v", n.IP, 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.IP.ToIP(),
|
|
|
|
HardwareAddr: n.MAC,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-08-17 09:27:54 +00:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-01-12 04:58:27 +00:00
|
|
|
func (dev *vxlanDevice) DelFDB(n neighbor) error {
|
|
|
|
log.V(4).Infof("calling DelFDB: %v, %v", n.IP, n.MAC)
|
|
|
|
return netlink.NeighDel(&netlink.Neigh{
|
|
|
|
LinkIndex: dev.link.Index,
|
|
|
|
Family: syscall.AF_BRIDGE,
|
|
|
|
Flags: netlink.NTF_SELF,
|
|
|
|
IP: n.IP.ToIP(),
|
|
|
|
HardwareAddr: n.MAC,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-08-17 09:27:54 +00:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-01-12 04:58:27 +00:00
|
|
|
func (dev *vxlanDevice) AddARP(n neighbor) error {
|
|
|
|
log.V(4).Infof("calling AddARP: %v, %v", n.IP, n.MAC)
|
|
|
|
return netlink.NeighSet(&netlink.Neigh{
|
|
|
|
LinkIndex: dev.link.Index,
|
|
|
|
State: netlink.NUD_PERMANENT,
|
|
|
|
Type: syscall.RTN_UNICAST,
|
|
|
|
IP: n.IP.ToIP(),
|
|
|
|
HardwareAddr: n.MAC,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-08-17 09:27:54 +00:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-01-12 04:58:27 +00:00
|
|
|
func (dev *vxlanDevice) DelARP(n neighbor) error {
|
|
|
|
log.V(4).Infof("calling DelARP: %v, %v", n.IP, n.MAC)
|
|
|
|
return netlink.NeighDel(&netlink.Neigh{
|
|
|
|
LinkIndex: dev.link.Index,
|
|
|
|
State: netlink.NUD_PERMANENT,
|
|
|
|
Type: syscall.RTN_UNICAST,
|
|
|
|
IP: n.IP.ToIP(),
|
|
|
|
HardwareAddr: n.MAC,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2021-08-17 09:27:54 +00:00
|
|
|
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,
|
|
|
|
})
|
|
|
|
}
|
|
|
|
|
2019-01-12 04:58:27 +00:00
|
|
|
func vxlanLinksIncompat(l1, l2 netlink.Link) string {
|
|
|
|
if l1.Type() != l2.Type() {
|
|
|
|
return fmt.Sprintf("link type: %v vs %v", l1.Type(), l2.Type())
|
|
|
|
}
|
|
|
|
|
|
|
|
v1 := l1.(*netlink.Vxlan)
|
|
|
|
v2 := l2.(*netlink.Vxlan)
|
|
|
|
|
|
|
|
if v1.VxlanId != v2.VxlanId {
|
|
|
|
return fmt.Sprintf("vni: %v vs %v", v1.VxlanId, v2.VxlanId)
|
|
|
|
}
|
|
|
|
|
|
|
|
if v1.VtepDevIndex > 0 && v2.VtepDevIndex > 0 && v1.VtepDevIndex != v2.VtepDevIndex {
|
|
|
|
return fmt.Sprintf("vtep (external) interface: %v vs %v", v1.VtepDevIndex, v2.VtepDevIndex)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(v1.SrcAddr) > 0 && len(v2.SrcAddr) > 0 && !v1.SrcAddr.Equal(v2.SrcAddr) {
|
|
|
|
return fmt.Sprintf("vtep (external) IP: %v vs %v", v1.SrcAddr, v2.SrcAddr)
|
|
|
|
}
|
|
|
|
|
|
|
|
if len(v1.Group) > 0 && len(v2.Group) > 0 && !v1.Group.Equal(v2.Group) {
|
|
|
|
return fmt.Sprintf("group address: %v vs %v", v1.Group, v2.Group)
|
|
|
|
}
|
|
|
|
|
|
|
|
if v1.L2miss != v2.L2miss {
|
|
|
|
return fmt.Sprintf("l2miss: %v vs %v", v1.L2miss, v2.L2miss)
|
|
|
|
}
|
|
|
|
|
|
|
|
if v1.Port > 0 && v2.Port > 0 && v1.Port != v2.Port {
|
|
|
|
return fmt.Sprintf("port: %v vs %v", v1.Port, v2.Port)
|
|
|
|
}
|
|
|
|
|
|
|
|
if v1.GBP != v2.GBP {
|
|
|
|
return fmt.Sprintf("gbp: %v vs %v", v1.GBP, v2.GBP)
|
|
|
|
}
|
|
|
|
|
|
|
|
return ""
|
|
|
|
}
|