mirror of
https://github.com/jsimonetti/rtnetlink.git
synced 2026-03-28 15:31:09 +01:00
Add drivers for bridge, macvlan, vlan, vxlan and add helpers to LinkService to use them (SetMaster, RemoveMaster) Signed-off-by: Jeroen Simonetti <jeroen@simonetti.nl>
434 lines
9.2 KiB
Go
434 lines
9.2 KiB
Go
package driver
|
|
|
|
import (
|
|
"encoding/binary"
|
|
"fmt"
|
|
"net"
|
|
|
|
"github.com/jsimonetti/rtnetlink/v2"
|
|
"github.com/jsimonetti/rtnetlink/v2/internal/unix"
|
|
"github.com/mdlayher/netlink"
|
|
)
|
|
|
|
// VxlanDFMode specifies how to handle DF flag in outer IPv4 header
|
|
type VxlanDFMode uint8
|
|
|
|
const (
|
|
// VxlanDFUnset indicates DF flag is not set (default)
|
|
VxlanDFUnset VxlanDFMode = iota
|
|
|
|
// VxlanDFSet indicates DF flag is set
|
|
VxlanDFSet
|
|
|
|
// VxlanDFInherit indicates DF flag is inherited from inner IPv4 header
|
|
VxlanDFInherit
|
|
)
|
|
|
|
func (v VxlanDFMode) String() string {
|
|
switch v {
|
|
case VxlanDFUnset:
|
|
return "unset"
|
|
case VxlanDFSet:
|
|
return "set"
|
|
case VxlanDFInherit:
|
|
return "inherit"
|
|
default:
|
|
return fmt.Sprintf("unknown VxlanDFMode value (%d)", v)
|
|
}
|
|
}
|
|
|
|
// VxlanPortRange specifies the range of source UDP ports
|
|
type VxlanPortRange struct {
|
|
Low uint16
|
|
High uint16
|
|
}
|
|
|
|
// Vxlan implements LinkDriver for the vxlan driver
|
|
type Vxlan struct {
|
|
// VXLAN Network Identifier (or VXLAN Segment ID) - required
|
|
ID *uint32
|
|
|
|
// Multicast group IP address to join (IPv4)
|
|
Group net.IP
|
|
|
|
// Multicast group IP address to join (IPv6)
|
|
Group6 net.IP
|
|
|
|
// Physical device to use for tunnel endpoint communication
|
|
Link *uint32
|
|
|
|
// Source IP address to use in outgoing packets (IPv4)
|
|
Local net.IP
|
|
|
|
// Source IP address to use in outgoing packets (IPv6)
|
|
Local6 net.IP
|
|
|
|
// TTL to use in outgoing packets
|
|
TTL *uint8
|
|
|
|
// TOS to use in outgoing packets
|
|
TOS *uint8
|
|
|
|
// Enable learning of source link addresses
|
|
Learning *bool
|
|
|
|
// Lifetime in seconds of FDB entries learnt by the kernel
|
|
Ageing *uint32
|
|
|
|
// Maximum number of FDB entries
|
|
Limit *uint32
|
|
|
|
// Range of source UDP ports to use
|
|
PortRange *VxlanPortRange
|
|
|
|
// Enable ARP proxy
|
|
Proxy *bool
|
|
|
|
// Enable route short circuit
|
|
RSC *bool
|
|
|
|
// Enable netlink LLADDR miss notifications
|
|
L2Miss *bool
|
|
|
|
// Enable netlink IP address miss notifications
|
|
L3Miss *bool
|
|
|
|
// Destination port for VXLAN traffic (default 4789)
|
|
Port *uint16
|
|
|
|
// Enable UDP checksums on transmit for outer IPv4
|
|
UDPCsum *bool
|
|
|
|
// Enable zero UDP checksums on transmit for outer IPv6
|
|
UDPZeroCsum6Tx *bool
|
|
|
|
// Allow zero UDP checksums on receive for outer IPv6
|
|
UDPZeroCsum6Rx *bool
|
|
|
|
// Enable remote checksum offload on transmit
|
|
RemCsumTx *bool
|
|
|
|
// Enable remote checksum offload on receive
|
|
RemCsumRx *bool
|
|
|
|
// Enable VXLAN Group Policy extension
|
|
GBP *bool
|
|
|
|
// Enable remote checksum offload without partial checksums
|
|
RemCsumNoPartial *bool
|
|
|
|
// Enable metadata collection mode
|
|
CollectMetadata *bool
|
|
|
|
// MPLS label to use for VXLAN encapsulation
|
|
Label *uint32
|
|
|
|
// Enable Generic Protocol Extension (VXLAN-GPE)
|
|
GPE *bool
|
|
|
|
// Inherit TTL from inner packet
|
|
TTLInherit *bool
|
|
|
|
// Specifies how to handle DF flag in outer IPv4 header
|
|
DF *VxlanDFMode
|
|
|
|
// Enable VXLAN VNI filtering
|
|
VNIFilter *bool
|
|
}
|
|
|
|
var _ rtnetlink.LinkDriver = &Vxlan{}
|
|
|
|
func (v *Vxlan) New() rtnetlink.LinkDriver {
|
|
return &Vxlan{}
|
|
}
|
|
|
|
func (v *Vxlan) Encode(ae *netlink.AttributeEncoder) error {
|
|
if v.ID != nil {
|
|
ae.Uint32(unix.IFLA_VXLAN_ID, *v.ID)
|
|
}
|
|
if v.Group != nil {
|
|
ip := v.Group.To4()
|
|
if ip == nil {
|
|
return fmt.Errorf("group must be an IPv4 address")
|
|
}
|
|
ae.Bytes(unix.IFLA_VXLAN_GROUP, ip)
|
|
}
|
|
if v.Group6 != nil {
|
|
// Check if it's actually an IPv6 address (not an IPv4 address)
|
|
if v.Group6.To4() != nil {
|
|
return fmt.Errorf("group6 must be an IPv6 address")
|
|
}
|
|
ip := v.Group6.To16()
|
|
if ip == nil {
|
|
return fmt.Errorf("group6 must be an IPv6 address")
|
|
}
|
|
ae.Bytes(unix.IFLA_VXLAN_GROUP6, ip)
|
|
}
|
|
if v.Link != nil {
|
|
ae.Uint32(unix.IFLA_VXLAN_LINK, *v.Link)
|
|
}
|
|
if v.Local != nil {
|
|
ip := v.Local.To4()
|
|
if ip == nil {
|
|
return fmt.Errorf("local must be an IPv4 address")
|
|
}
|
|
ae.Bytes(unix.IFLA_VXLAN_LOCAL, ip)
|
|
}
|
|
if v.Local6 != nil {
|
|
// Check if it's actually an IPv6 address (not an IPv4 address)
|
|
if v.Local6.To4() != nil {
|
|
return fmt.Errorf("local6 must be an IPv6 address")
|
|
}
|
|
ip := v.Local6.To16()
|
|
if ip == nil {
|
|
return fmt.Errorf("local6 must be an IPv6 address")
|
|
}
|
|
ae.Bytes(unix.IFLA_VXLAN_LOCAL6, ip)
|
|
}
|
|
if v.TTL != nil {
|
|
ae.Uint8(unix.IFLA_VXLAN_TTL, *v.TTL)
|
|
}
|
|
if v.TOS != nil {
|
|
ae.Uint8(unix.IFLA_VXLAN_TOS, *v.TOS)
|
|
}
|
|
if v.Learning != nil {
|
|
var val uint8
|
|
if *v.Learning {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_LEARNING, val)
|
|
}
|
|
if v.Ageing != nil {
|
|
ae.Uint32(unix.IFLA_VXLAN_AGEING, *v.Ageing)
|
|
}
|
|
if v.Limit != nil {
|
|
ae.Uint32(unix.IFLA_VXLAN_LIMIT, *v.Limit)
|
|
}
|
|
if v.PortRange != nil {
|
|
buf := make([]byte, 4)
|
|
binary.BigEndian.PutUint16(buf[0:2], v.PortRange.Low)
|
|
binary.BigEndian.PutUint16(buf[2:4], v.PortRange.High)
|
|
ae.Bytes(unix.IFLA_VXLAN_PORT_RANGE, buf)
|
|
}
|
|
if v.Proxy != nil {
|
|
var val uint8
|
|
if *v.Proxy {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_PROXY, val)
|
|
}
|
|
if v.RSC != nil {
|
|
var val uint8
|
|
if *v.RSC {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_RSC, val)
|
|
}
|
|
if v.L2Miss != nil {
|
|
var val uint8
|
|
if *v.L2Miss {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_L2MISS, val)
|
|
}
|
|
if v.L3Miss != nil {
|
|
var val uint8
|
|
if *v.L3Miss {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_L3MISS, val)
|
|
}
|
|
if v.Port != nil {
|
|
// Port must be in network byte order (big-endian)
|
|
buf := make([]byte, 2)
|
|
binary.BigEndian.PutUint16(buf, *v.Port)
|
|
ae.Bytes(unix.IFLA_VXLAN_PORT, buf)
|
|
}
|
|
if v.UDPCsum != nil {
|
|
var val uint8
|
|
if *v.UDPCsum {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_UDP_CSUM, val)
|
|
}
|
|
if v.UDPZeroCsum6Tx != nil {
|
|
var val uint8
|
|
if *v.UDPZeroCsum6Tx {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_UDP_ZERO_CSUM6_TX, val)
|
|
}
|
|
if v.UDPZeroCsum6Rx != nil {
|
|
var val uint8
|
|
if *v.UDPZeroCsum6Rx {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_UDP_ZERO_CSUM6_RX, val)
|
|
}
|
|
if v.RemCsumTx != nil {
|
|
var val uint8
|
|
if *v.RemCsumTx {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_REMCSUM_TX, val)
|
|
}
|
|
if v.RemCsumRx != nil {
|
|
var val uint8
|
|
if *v.RemCsumRx {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_REMCSUM_RX, val)
|
|
}
|
|
if v.GBP != nil {
|
|
if *v.GBP {
|
|
ae.Uint32(unix.IFLA_VXLAN_GBP, 0)
|
|
}
|
|
}
|
|
if v.RemCsumNoPartial != nil {
|
|
if *v.RemCsumNoPartial {
|
|
ae.Uint32(unix.IFLA_VXLAN_REMCSUM_NOPARTIAL, 0)
|
|
}
|
|
}
|
|
if v.CollectMetadata != nil {
|
|
var val uint8
|
|
if *v.CollectMetadata {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_COLLECT_METADATA, val)
|
|
}
|
|
if v.Label != nil {
|
|
ae.Uint32(unix.IFLA_VXLAN_LABEL, *v.Label)
|
|
}
|
|
if v.GPE != nil {
|
|
if *v.GPE {
|
|
ae.Uint32(unix.IFLA_VXLAN_GPE, 0)
|
|
}
|
|
}
|
|
if v.TTLInherit != nil {
|
|
var val uint8
|
|
if *v.TTLInherit {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_TTL_INHERIT, val)
|
|
}
|
|
if v.DF != nil {
|
|
ae.Uint8(unix.IFLA_VXLAN_DF, uint8(*v.DF))
|
|
}
|
|
if v.VNIFilter != nil {
|
|
var val uint8
|
|
if *v.VNIFilter {
|
|
val = 1
|
|
}
|
|
ae.Uint8(unix.IFLA_VXLAN_VNIFILTER, val)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func (v *Vxlan) Decode(ad *netlink.AttributeDecoder) error {
|
|
for ad.Next() {
|
|
switch ad.Type() {
|
|
case unix.IFLA_VXLAN_ID:
|
|
val := ad.Uint32()
|
|
v.ID = &val
|
|
case unix.IFLA_VXLAN_GROUP:
|
|
v.Group = net.IP(ad.Bytes())
|
|
case unix.IFLA_VXLAN_GROUP6:
|
|
v.Group6 = net.IP(ad.Bytes())
|
|
case unix.IFLA_VXLAN_LINK:
|
|
val := ad.Uint32()
|
|
v.Link = &val
|
|
case unix.IFLA_VXLAN_LOCAL:
|
|
v.Local = net.IP(ad.Bytes())
|
|
case unix.IFLA_VXLAN_LOCAL6:
|
|
v.Local6 = net.IP(ad.Bytes())
|
|
case unix.IFLA_VXLAN_TTL:
|
|
val := ad.Uint8()
|
|
v.TTL = &val
|
|
case unix.IFLA_VXLAN_TOS:
|
|
val := ad.Uint8()
|
|
v.TOS = &val
|
|
case unix.IFLA_VXLAN_LEARNING:
|
|
val := ad.Uint8() != 0
|
|
v.Learning = &val
|
|
case unix.IFLA_VXLAN_AGEING:
|
|
val := ad.Uint32()
|
|
v.Ageing = &val
|
|
case unix.IFLA_VXLAN_LIMIT:
|
|
val := ad.Uint32()
|
|
v.Limit = &val
|
|
case unix.IFLA_VXLAN_PORT_RANGE:
|
|
buf := ad.Bytes()
|
|
if len(buf) >= 4 {
|
|
v.PortRange = &VxlanPortRange{
|
|
Low: binary.BigEndian.Uint16(buf[0:2]),
|
|
High: binary.BigEndian.Uint16(buf[2:4]),
|
|
}
|
|
}
|
|
case unix.IFLA_VXLAN_PROXY:
|
|
val := ad.Uint8() != 0
|
|
v.Proxy = &val
|
|
case unix.IFLA_VXLAN_RSC:
|
|
val := ad.Uint8() != 0
|
|
v.RSC = &val
|
|
case unix.IFLA_VXLAN_L2MISS:
|
|
val := ad.Uint8() != 0
|
|
v.L2Miss = &val
|
|
case unix.IFLA_VXLAN_L3MISS:
|
|
val := ad.Uint8() != 0
|
|
v.L3Miss = &val
|
|
case unix.IFLA_VXLAN_PORT:
|
|
// Port is in network byte order (big-endian)
|
|
buf := ad.Bytes()
|
|
if len(buf) >= 2 {
|
|
val := binary.BigEndian.Uint16(buf)
|
|
v.Port = &val
|
|
}
|
|
case unix.IFLA_VXLAN_UDP_CSUM:
|
|
val := ad.Uint8() != 0
|
|
v.UDPCsum = &val
|
|
case unix.IFLA_VXLAN_UDP_ZERO_CSUM6_TX:
|
|
val := ad.Uint8() != 0
|
|
v.UDPZeroCsum6Tx = &val
|
|
case unix.IFLA_VXLAN_UDP_ZERO_CSUM6_RX:
|
|
val := ad.Uint8() != 0
|
|
v.UDPZeroCsum6Rx = &val
|
|
case unix.IFLA_VXLAN_REMCSUM_TX:
|
|
val := ad.Uint8() != 0
|
|
v.RemCsumTx = &val
|
|
case unix.IFLA_VXLAN_REMCSUM_RX:
|
|
val := ad.Uint8() != 0
|
|
v.RemCsumRx = &val
|
|
case unix.IFLA_VXLAN_GBP:
|
|
val := true
|
|
v.GBP = &val
|
|
case unix.IFLA_VXLAN_REMCSUM_NOPARTIAL:
|
|
val := true
|
|
v.RemCsumNoPartial = &val
|
|
case unix.IFLA_VXLAN_COLLECT_METADATA:
|
|
val := ad.Uint8() != 0
|
|
v.CollectMetadata = &val
|
|
case unix.IFLA_VXLAN_LABEL:
|
|
val := ad.Uint32()
|
|
v.Label = &val
|
|
case unix.IFLA_VXLAN_GPE:
|
|
val := true
|
|
v.GPE = &val
|
|
case unix.IFLA_VXLAN_TTL_INHERIT:
|
|
val := ad.Uint8() != 0
|
|
v.TTLInherit = &val
|
|
case unix.IFLA_VXLAN_DF:
|
|
val := VxlanDFMode(ad.Uint8())
|
|
v.DF = &val
|
|
case unix.IFLA_VXLAN_VNIFILTER:
|
|
val := ad.Uint8() != 0
|
|
v.VNIFilter = &val
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func (*Vxlan) Kind() string {
|
|
return "vxlan"
|
|
}
|