rtnetlink/driver/bridge.go
Jeroen Simonetti 5c41262525
Implement additional drivers (#280)
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>
2025-10-30 22:55:44 +01:00

676 lines
18 KiB
Go

package driver
import (
"fmt"
"net"
"github.com/jsimonetti/rtnetlink/v2"
"github.com/jsimonetti/rtnetlink/v2/internal/unix"
"github.com/mdlayher/netlink"
)
// BridgeStpState represents the Spanning Tree Protocol state.
type BridgeStpState uint32
// STP states.
const (
BridgeStpStateDisabled BridgeStpState = 0
BridgeStpStateEnabled BridgeStpState = 1
)
// String returns a string representation of the BridgeStpState.
func (s BridgeStpState) String() string {
switch s {
case BridgeStpStateDisabled:
return "disabled"
case BridgeStpStateEnabled:
return "enabled"
default:
return fmt.Sprintf("unknown BridgeStpState value (%d)", uint32(s))
}
}
// BridgeEnable represents an enable/disable flag for various bridge features.
type BridgeEnable uint8
// Enable/disable states.
const (
BridgeEnableDisabled BridgeEnable = 0
BridgeEnableEnabled BridgeEnable = 1
)
// String returns a string representation of the BridgeEnable.
func (e BridgeEnable) String() string {
switch e {
case BridgeEnableDisabled:
return "disabled"
case BridgeEnableEnabled:
return "enabled"
default:
return fmt.Sprintf("unknown BridgeEnable value (%d)", uint8(e))
}
}
// Bridge implements LinkDriver for the bridge driver
type Bridge struct {
// For more detailed information see https://www.kernel.org/doc/html/latest/networking/bridge.html
// Forward delay time in centiseconds (default: 1500, which is 15 seconds)
ForwardDelay *uint32
// Hello time in centiseconds (default: 200, which is 2 seconds)
HelloTime *uint32
// Maximum message age in centiseconds (default: 2000, which is 20 seconds)
MaxAge *uint32
// Ageing time in centiseconds (default: 30000, which is 300 seconds/5 minutes)
AgeingTime *uint32
// STP state (disabled/enabled)
StpState *BridgeStpState
// Bridge priority (default: 32768)
Priority *uint16
// VLAN filtering
VlanFiltering *BridgeEnable
// VLAN protocol (e.g., VlanProtocol8021Q for 802.1Q, VlanProtocol8021AD for 802.1ad)
VlanProtocol *VlanProtocol
// Group forward mask
GroupFwdMask *uint16
// Group address (MAC address)
GroupAddr net.HardwareAddr
// FDB flush - triggers a flush of the forwarding database
FdbFlush *uint8
// Multicast router setting (0=disabled, 1=enabled, 2=auto)
McastRouter *uint8
// Multicast snooping
McastSnooping *BridgeEnable
// Multicast query use IFADDR
McastQueryUseIfaddr *BridgeEnable
// Multicast querier
McastQuerier *BridgeEnable
// Multicast hash elasticity
McastHashElasticity *uint32
// Multicast hash max
McastHashMax *uint32
// Multicast last member count
McastLastMemberCnt *uint32
// Multicast startup query count
McastStartupQueryCnt *uint32
// Multicast last member interval in centiseconds
McastLastMemberIntvl *uint64
// Multicast membership interval in centiseconds
McastMembershipIntvl *uint64
// Multicast querier interval in centiseconds
McastQuerierIntvl *uint64
// Multicast query interval in centiseconds
McastQueryIntvl *uint64
// Multicast query response interval in centiseconds
McastQueryResponseIntvl *uint64
// Multicast startup query interval in centiseconds
McastStartupQueryIntvl *uint64
// NF call iptables
NfCallIptables *BridgeEnable
// NF call ip6tables
NfCallIp6tables *BridgeEnable
// NF call arptables
NfCallArptables *BridgeEnable
// VLAN default PVID
VlanDefaultPvid *uint16
// VLAN stats enabled
VlanStatsEnabled *BridgeEnable
// Multicast stats enabled
McastStatsEnabled *BridgeEnable
// Multicast IGMP version (2 or 3)
McastIgmpVersion *uint8
// Multicast MLD version (1 or 2)
McastMldVersion *uint8
// VLAN stats per port
VlanStatsPerPort *BridgeEnable
// FDB max learned entries (0=unlimited)
FdbMaxLearned *uint32
}
var _ rtnetlink.LinkDriver = &Bridge{}
func (b *Bridge) New() rtnetlink.LinkDriver {
return &Bridge{}
}
func (b *Bridge) Encode(ae *netlink.AttributeEncoder) error {
if b.ForwardDelay != nil {
ae.Uint32(unix.IFLA_BR_FORWARD_DELAY, *b.ForwardDelay)
}
if b.HelloTime != nil {
ae.Uint32(unix.IFLA_BR_HELLO_TIME, *b.HelloTime)
}
if b.MaxAge != nil {
ae.Uint32(unix.IFLA_BR_MAX_AGE, *b.MaxAge)
}
if b.AgeingTime != nil {
ae.Uint32(unix.IFLA_BR_AGEING_TIME, *b.AgeingTime)
}
if b.StpState != nil {
ae.Uint32(unix.IFLA_BR_STP_STATE, uint32(*b.StpState))
}
if b.Priority != nil {
ae.Uint16(unix.IFLA_BR_PRIORITY, *b.Priority)
}
if b.VlanFiltering != nil {
ae.Uint8(unix.IFLA_BR_VLAN_FILTERING, uint8(*b.VlanFiltering))
}
if b.VlanProtocol != nil {
ae.Uint16(unix.IFLA_BR_VLAN_PROTOCOL, uint16(*b.VlanProtocol))
}
if b.GroupFwdMask != nil {
ae.Uint16(unix.IFLA_BR_GROUP_FWD_MASK, *b.GroupFwdMask)
}
if b.GroupAddr != nil {
ae.Bytes(unix.IFLA_BR_GROUP_ADDR, []byte(b.GroupAddr))
}
if b.FdbFlush != nil {
ae.Uint8(unix.IFLA_BR_FDB_FLUSH, *b.FdbFlush)
}
if b.McastRouter != nil {
ae.Uint8(unix.IFLA_BR_MCAST_ROUTER, *b.McastRouter)
}
if b.McastSnooping != nil {
ae.Uint8(unix.IFLA_BR_MCAST_SNOOPING, uint8(*b.McastSnooping))
}
if b.McastQueryUseIfaddr != nil {
ae.Uint8(unix.IFLA_BR_MCAST_QUERY_USE_IFADDR, uint8(*b.McastQueryUseIfaddr))
}
if b.McastQuerier != nil {
ae.Uint8(unix.IFLA_BR_MCAST_QUERIER, uint8(*b.McastQuerier))
}
if b.McastHashElasticity != nil {
ae.Uint32(unix.IFLA_BR_MCAST_HASH_ELASTICITY, *b.McastHashElasticity)
}
if b.McastHashMax != nil {
ae.Uint32(unix.IFLA_BR_MCAST_HASH_MAX, *b.McastHashMax)
}
if b.McastLastMemberCnt != nil {
ae.Uint32(unix.IFLA_BR_MCAST_LAST_MEMBER_CNT, *b.McastLastMemberCnt)
}
if b.McastStartupQueryCnt != nil {
ae.Uint32(unix.IFLA_BR_MCAST_STARTUP_QUERY_CNT, *b.McastStartupQueryCnt)
}
if b.McastLastMemberIntvl != nil {
ae.Uint64(unix.IFLA_BR_MCAST_LAST_MEMBER_INTVL, *b.McastLastMemberIntvl)
}
if b.McastMembershipIntvl != nil {
ae.Uint64(unix.IFLA_BR_MCAST_MEMBERSHIP_INTVL, *b.McastMembershipIntvl)
}
if b.McastQuerierIntvl != nil {
ae.Uint64(unix.IFLA_BR_MCAST_QUERIER_INTVL, *b.McastQuerierIntvl)
}
if b.McastQueryIntvl != nil {
ae.Uint64(unix.IFLA_BR_MCAST_QUERY_INTVL, *b.McastQueryIntvl)
}
if b.McastQueryResponseIntvl != nil {
ae.Uint64(unix.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, *b.McastQueryResponseIntvl)
}
if b.McastStartupQueryIntvl != nil {
ae.Uint64(unix.IFLA_BR_MCAST_STARTUP_QUERY_INTVL, *b.McastStartupQueryIntvl)
}
if b.NfCallIptables != nil {
ae.Uint8(unix.IFLA_BR_NF_CALL_IPTABLES, uint8(*b.NfCallIptables))
}
if b.NfCallIp6tables != nil {
ae.Uint8(unix.IFLA_BR_NF_CALL_IP6TABLES, uint8(*b.NfCallIp6tables))
}
if b.NfCallArptables != nil {
ae.Uint8(unix.IFLA_BR_NF_CALL_ARPTABLES, uint8(*b.NfCallArptables))
}
if b.VlanDefaultPvid != nil {
ae.Uint16(unix.IFLA_BR_VLAN_DEFAULT_PVID, *b.VlanDefaultPvid)
}
if b.VlanStatsEnabled != nil {
ae.Uint8(unix.IFLA_BR_VLAN_STATS_ENABLED, uint8(*b.VlanStatsEnabled))
}
if b.McastStatsEnabled != nil {
ae.Uint8(unix.IFLA_BR_MCAST_STATS_ENABLED, uint8(*b.McastStatsEnabled))
}
if b.McastIgmpVersion != nil {
ae.Uint8(unix.IFLA_BR_MCAST_IGMP_VERSION, *b.McastIgmpVersion)
}
if b.McastMldVersion != nil {
ae.Uint8(unix.IFLA_BR_MCAST_MLD_VERSION, *b.McastMldVersion)
}
if b.VlanStatsPerPort != nil {
ae.Uint8(unix.IFLA_BR_VLAN_STATS_PER_PORT, uint8(*b.VlanStatsPerPort))
}
if b.FdbMaxLearned != nil {
ae.Uint32(unix.IFLA_BR_FDB_MAX_LEARNED, *b.FdbMaxLearned)
}
return nil
}
func (b *Bridge) Decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.IFLA_BR_FORWARD_DELAY:
v := ad.Uint32()
b.ForwardDelay = &v
case unix.IFLA_BR_HELLO_TIME:
v := ad.Uint32()
b.HelloTime = &v
case unix.IFLA_BR_MAX_AGE:
v := ad.Uint32()
b.MaxAge = &v
case unix.IFLA_BR_AGEING_TIME:
v := ad.Uint32()
b.AgeingTime = &v
case unix.IFLA_BR_STP_STATE:
v := BridgeStpState(ad.Uint32())
b.StpState = &v
case unix.IFLA_BR_PRIORITY:
v := ad.Uint16()
b.Priority = &v
case unix.IFLA_BR_VLAN_FILTERING:
v := BridgeEnable(ad.Uint8())
b.VlanFiltering = &v
case unix.IFLA_BR_VLAN_PROTOCOL:
v := VlanProtocol(ad.Uint16())
b.VlanProtocol = &v
case unix.IFLA_BR_GROUP_FWD_MASK:
v := ad.Uint16()
b.GroupFwdMask = &v
case unix.IFLA_BR_GROUP_ADDR:
b.GroupAddr = net.HardwareAddr(ad.Bytes())
case unix.IFLA_BR_FDB_FLUSH:
v := ad.Uint8()
b.FdbFlush = &v
case unix.IFLA_BR_MCAST_ROUTER:
v := ad.Uint8()
b.McastRouter = &v
case unix.IFLA_BR_MCAST_SNOOPING:
v := BridgeEnable(ad.Uint8())
b.McastSnooping = &v
case unix.IFLA_BR_MCAST_QUERY_USE_IFADDR:
v := BridgeEnable(ad.Uint8())
b.McastQueryUseIfaddr = &v
case unix.IFLA_BR_MCAST_QUERIER:
v := BridgeEnable(ad.Uint8())
b.McastQuerier = &v
case unix.IFLA_BR_MCAST_HASH_ELASTICITY:
v := ad.Uint32()
b.McastHashElasticity = &v
case unix.IFLA_BR_MCAST_HASH_MAX:
v := ad.Uint32()
b.McastHashMax = &v
case unix.IFLA_BR_MCAST_LAST_MEMBER_CNT:
v := ad.Uint32()
b.McastLastMemberCnt = &v
case unix.IFLA_BR_MCAST_STARTUP_QUERY_CNT:
v := ad.Uint32()
b.McastStartupQueryCnt = &v
case unix.IFLA_BR_MCAST_LAST_MEMBER_INTVL:
v := ad.Uint64()
b.McastLastMemberIntvl = &v
case unix.IFLA_BR_MCAST_MEMBERSHIP_INTVL:
v := ad.Uint64()
b.McastMembershipIntvl = &v
case unix.IFLA_BR_MCAST_QUERIER_INTVL:
v := ad.Uint64()
b.McastQuerierIntvl = &v
case unix.IFLA_BR_MCAST_QUERY_INTVL:
v := ad.Uint64()
b.McastQueryIntvl = &v
case unix.IFLA_BR_MCAST_QUERY_RESPONSE_INTVL:
v := ad.Uint64()
b.McastQueryResponseIntvl = &v
case unix.IFLA_BR_MCAST_STARTUP_QUERY_INTVL:
v := ad.Uint64()
b.McastStartupQueryIntvl = &v
case unix.IFLA_BR_NF_CALL_IPTABLES:
v := BridgeEnable(ad.Uint8())
b.NfCallIptables = &v
case unix.IFLA_BR_NF_CALL_IP6TABLES:
v := BridgeEnable(ad.Uint8())
b.NfCallIp6tables = &v
case unix.IFLA_BR_NF_CALL_ARPTABLES:
v := BridgeEnable(ad.Uint8())
b.NfCallArptables = &v
case unix.IFLA_BR_VLAN_DEFAULT_PVID:
v := ad.Uint16()
b.VlanDefaultPvid = &v
case unix.IFLA_BR_VLAN_STATS_ENABLED:
v := BridgeEnable(ad.Uint8())
b.VlanStatsEnabled = &v
case unix.IFLA_BR_MCAST_STATS_ENABLED:
v := BridgeEnable(ad.Uint8())
b.McastStatsEnabled = &v
case unix.IFLA_BR_MCAST_IGMP_VERSION:
v := ad.Uint8()
b.McastIgmpVersion = &v
case unix.IFLA_BR_MCAST_MLD_VERSION:
v := ad.Uint8()
b.McastMldVersion = &v
case unix.IFLA_BR_VLAN_STATS_PER_PORT:
v := BridgeEnable(ad.Uint8())
b.VlanStatsPerPort = &v
case unix.IFLA_BR_FDB_MAX_LEARNED:
v := ad.Uint32()
b.FdbMaxLearned = &v
}
}
return nil
}
func (*Bridge) Kind() string {
return "bridge"
}
// BridgePortState specifies the port state in Spanning Tree Protocol
type BridgePortState uint8
const (
BridgePortStateDisabled BridgePortState = iota
BridgePortStateListening
BridgePortStateLearning
BridgePortStateForwarding
BridgePortStateBlocking
)
func (s BridgePortState) String() string {
switch s {
case BridgePortStateDisabled:
return "disabled"
case BridgePortStateListening:
return "listening"
case BridgePortStateLearning:
return "learning"
case BridgePortStateForwarding:
return "forwarding"
case BridgePortStateBlocking:
return "blocking"
default:
return fmt.Sprintf("unknown BridgePortState value (%d)", s)
}
}
// BridgePort implements LinkSlaveDriver for bridge port/slave configuration
type BridgePort struct {
// Port state (disabled, listening, learning, forwarding, blocking)
State *BridgePortState
// Port priority (default: 32)
Priority *uint16
// Port cost (default: automatically calculated from link speed)
Cost *uint32
// Hairpin mode - allow packets to be sent back out the port they were received on
Mode *BridgeEnable
// BPDU guard - if enabled, STP BPDUs received on the port will cause it to be disabled
Guard *BridgeEnable
// Root guard - if enabled, the port will not become a root port
Protect *BridgeEnable
// Fast leave - immediately remove the port from multicast group when a leave message is received
FastLeave *BridgeEnable
// Learning - controls whether the bridge will learn MAC addresses from packets on this port
Learning *BridgeEnable
// Unicast flood - controls flooding of unicast traffic
UnicastFlood *BridgeEnable
// Proxy ARP
ProxyArp *BridgeEnable
// Learning sync
LearningSync *BridgeEnable
// Proxy ARP WiFi
ProxyArpWifi *BridgeEnable
// Multicast router (0=disabled, 1=enabled, 2=auto)
MulticastRouter *uint8
// Multicast fast leave
McastFlood *BridgeEnable
// Multicast to unicast
McastToUcast *BridgeEnable
// VLAN tunnel
VlanTunnel *BridgeEnable
// Broadcast flood
BcastFlood *BridgeEnable
// Group forward mask
GroupFwdMask *uint16
// Neighbor suppression
NeighSuppress *BridgeEnable
// Isolated - prevents communication between isolated ports
Isolated *BridgeEnable
// Backup port index
BackupPort *uint32
// Locked - prevents learning of MAC addresses
Locked *BridgeEnable
// MAB (MAC Authentication Bypass)
Mab *BridgeEnable
// Neighbor VLAN suppression
NeighVlanSuppress *BridgeEnable
// Backup nexthop ID
BackupNhid *uint32
}
var _ rtnetlink.LinkSlaveDriver = &BridgePort{}
func (bp *BridgePort) New() rtnetlink.LinkDriver {
return &BridgePort{}
}
func (bp *BridgePort) Slave() {}
func (bp *BridgePort) Encode(ae *netlink.AttributeEncoder) error {
if bp.State != nil {
ae.Uint8(unix.IFLA_BRPORT_STATE, uint8(*bp.State))
}
if bp.Priority != nil {
ae.Uint16(unix.IFLA_BRPORT_PRIORITY, *bp.Priority)
}
if bp.Cost != nil {
ae.Uint32(unix.IFLA_BRPORT_COST, *bp.Cost)
}
if bp.Mode != nil {
ae.Uint8(unix.IFLA_BRPORT_MODE, uint8(*bp.Mode))
}
if bp.Guard != nil {
ae.Uint8(unix.IFLA_BRPORT_GUARD, uint8(*bp.Guard))
}
if bp.Protect != nil {
ae.Uint8(unix.IFLA_BRPORT_PROTECT, uint8(*bp.Protect))
}
if bp.FastLeave != nil {
ae.Uint8(unix.IFLA_BRPORT_FAST_LEAVE, uint8(*bp.FastLeave))
}
if bp.Learning != nil {
ae.Uint8(unix.IFLA_BRPORT_LEARNING, uint8(*bp.Learning))
}
if bp.UnicastFlood != nil {
ae.Uint8(unix.IFLA_BRPORT_UNICAST_FLOOD, uint8(*bp.UnicastFlood))
}
if bp.ProxyArp != nil {
ae.Uint8(unix.IFLA_BRPORT_PROXYARP, uint8(*bp.ProxyArp))
}
if bp.LearningSync != nil {
ae.Uint8(unix.IFLA_BRPORT_LEARNING_SYNC, uint8(*bp.LearningSync))
}
if bp.ProxyArpWifi != nil {
ae.Uint8(unix.IFLA_BRPORT_PROXYARP_WIFI, uint8(*bp.ProxyArpWifi))
}
if bp.MulticastRouter != nil {
ae.Uint8(unix.IFLA_BRPORT_MULTICAST_ROUTER, *bp.MulticastRouter)
}
if bp.McastFlood != nil {
ae.Uint8(unix.IFLA_BRPORT_MCAST_FLOOD, uint8(*bp.McastFlood))
}
if bp.McastToUcast != nil {
ae.Uint8(unix.IFLA_BRPORT_MCAST_TO_UCAST, uint8(*bp.McastToUcast))
}
if bp.VlanTunnel != nil {
ae.Uint8(unix.IFLA_BRPORT_VLAN_TUNNEL, uint8(*bp.VlanTunnel))
}
if bp.BcastFlood != nil {
ae.Uint8(unix.IFLA_BRPORT_BCAST_FLOOD, uint8(*bp.BcastFlood))
}
if bp.GroupFwdMask != nil {
ae.Uint16(unix.IFLA_BRPORT_GROUP_FWD_MASK, *bp.GroupFwdMask)
}
if bp.NeighSuppress != nil {
ae.Uint8(unix.IFLA_BRPORT_NEIGH_SUPPRESS, uint8(*bp.NeighSuppress))
}
if bp.Isolated != nil {
ae.Uint8(unix.IFLA_BRPORT_ISOLATED, uint8(*bp.Isolated))
}
if bp.BackupPort != nil {
ae.Uint32(unix.IFLA_BRPORT_BACKUP_PORT, *bp.BackupPort)
}
if bp.Locked != nil {
ae.Uint8(unix.IFLA_BRPORT_LOCKED, uint8(*bp.Locked))
}
if bp.Mab != nil {
ae.Uint8(unix.IFLA_BRPORT_MAB, uint8(*bp.Mab))
}
if bp.NeighVlanSuppress != nil {
ae.Uint8(unix.IFLA_BRPORT_NEIGH_VLAN_SUPPRESS, uint8(*bp.NeighVlanSuppress))
}
if bp.BackupNhid != nil {
ae.Uint32(unix.IFLA_BRPORT_BACKUP_NHID, *bp.BackupNhid)
}
return nil
}
func (bp *BridgePort) Decode(ad *netlink.AttributeDecoder) error {
for ad.Next() {
switch ad.Type() {
case unix.IFLA_BRPORT_STATE:
v := BridgePortState(ad.Uint8())
bp.State = &v
case unix.IFLA_BRPORT_PRIORITY:
v := ad.Uint16()
bp.Priority = &v
case unix.IFLA_BRPORT_COST:
v := ad.Uint32()
bp.Cost = &v
case unix.IFLA_BRPORT_MODE:
v := BridgeEnable(ad.Uint8())
bp.Mode = &v
case unix.IFLA_BRPORT_GUARD:
v := BridgeEnable(ad.Uint8())
bp.Guard = &v
case unix.IFLA_BRPORT_PROTECT:
v := BridgeEnable(ad.Uint8())
bp.Protect = &v
case unix.IFLA_BRPORT_FAST_LEAVE:
v := BridgeEnable(ad.Uint8())
bp.FastLeave = &v
case unix.IFLA_BRPORT_LEARNING:
v := BridgeEnable(ad.Uint8())
bp.Learning = &v
case unix.IFLA_BRPORT_UNICAST_FLOOD:
v := BridgeEnable(ad.Uint8())
bp.UnicastFlood = &v
case unix.IFLA_BRPORT_PROXYARP:
v := BridgeEnable(ad.Uint8())
bp.ProxyArp = &v
case unix.IFLA_BRPORT_LEARNING_SYNC:
v := BridgeEnable(ad.Uint8())
bp.LearningSync = &v
case unix.IFLA_BRPORT_PROXYARP_WIFI:
v := BridgeEnable(ad.Uint8())
bp.ProxyArpWifi = &v
case unix.IFLA_BRPORT_MULTICAST_ROUTER:
v := ad.Uint8()
bp.MulticastRouter = &v
case unix.IFLA_BRPORT_MCAST_FLOOD:
v := BridgeEnable(ad.Uint8())
bp.McastFlood = &v
case unix.IFLA_BRPORT_MCAST_TO_UCAST:
v := BridgeEnable(ad.Uint8())
bp.McastToUcast = &v
case unix.IFLA_BRPORT_VLAN_TUNNEL:
v := BridgeEnable(ad.Uint8())
bp.VlanTunnel = &v
case unix.IFLA_BRPORT_BCAST_FLOOD:
v := BridgeEnable(ad.Uint8())
bp.BcastFlood = &v
case unix.IFLA_BRPORT_GROUP_FWD_MASK:
v := ad.Uint16()
bp.GroupFwdMask = &v
case unix.IFLA_BRPORT_NEIGH_SUPPRESS:
v := BridgeEnable(ad.Uint8())
bp.NeighSuppress = &v
case unix.IFLA_BRPORT_ISOLATED:
v := BridgeEnable(ad.Uint8())
bp.Isolated = &v
case unix.IFLA_BRPORT_BACKUP_PORT:
v := ad.Uint32()
bp.BackupPort = &v
case unix.IFLA_BRPORT_LOCKED:
v := BridgeEnable(ad.Uint8())
bp.Locked = &v
case unix.IFLA_BRPORT_MAB:
v := BridgeEnable(ad.Uint8())
bp.Mab = &v
case unix.IFLA_BRPORT_NEIGH_VLAN_SUPPRESS:
v := BridgeEnable(ad.Uint8())
bp.NeighVlanSuppress = &v
case unix.IFLA_BRPORT_BACKUP_NHID:
v := ad.Uint32()
bp.BackupNhid = &v
}
}
return nil
}
func (*BridgePort) Kind() string {
return "bridge"
}