mirror of
https://github.com/vishvananda/netlink.git
synced 2025-11-03 01:53:26 +08:00
feat: add vlanid - tunnelid mapping support
This commit is contained in:
185
bridge_linux.go
185
bridge_linux.go
@@ -3,11 +3,102 @@ package netlink
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"syscall"
|
||||
|
||||
"github.com/vishvananda/netlink/nl"
|
||||
"golang.org/x/sys/unix"
|
||||
)
|
||||
|
||||
// BridgeVlanTunnelShow gets vlanid-tunnelid mapping.
|
||||
// Equivalent to: `bridge vlan tunnelshow`
|
||||
//
|
||||
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
|
||||
// or incomplete.
|
||||
func BridgeVlanTunnelShow() ([]nl.TunnelInfo, error) {
|
||||
return pkgHandle.BridgeVlanTunnelShow()
|
||||
}
|
||||
|
||||
func (h *Handle) BridgeVlanTunnelShow() ([]nl.TunnelInfo, error) {
|
||||
req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
|
||||
msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
|
||||
req.AddData(msg)
|
||||
req.AddData(nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
|
||||
|
||||
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
|
||||
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
|
||||
return nil, executeErr
|
||||
}
|
||||
ret := make([]nl.TunnelInfo, 0)
|
||||
for _, m := range msgs {
|
||||
msg := nl.DeserializeIfInfomsg(m)
|
||||
|
||||
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
for _, attr := range attrs {
|
||||
switch attr.Attr.Type {
|
||||
case unix.IFLA_AF_SPEC:
|
||||
nestedAttrs, err := nl.ParseRouteAttr(attr.Value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse nested attr %v", err)
|
||||
}
|
||||
for _, nestAttr := range nestedAttrs {
|
||||
switch nestAttr.Attr.Type {
|
||||
case nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO:
|
||||
ret, err = parseTunnelInfo(&nestAttr, ret)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse tunnelinfo %v", err)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return ret, executeErr
|
||||
}
|
||||
|
||||
func parseTunnelInfo(nestAttr *syscall.NetlinkRouteAttr, results []nl.TunnelInfo) ([]nl.TunnelInfo, error) {
|
||||
tunnelInfos, err := nl.ParseRouteAttr(nestAttr.Value)
|
||||
if err != nil {
|
||||
return nil, fmt.Errorf("failed to parse nested attr %v", err)
|
||||
}
|
||||
var tunnelId uint32
|
||||
var vid uint16
|
||||
var flag uint16
|
||||
for _, tunnelInfo := range tunnelInfos {
|
||||
switch tunnelInfo.Attr.Type {
|
||||
case nl.IFLA_BRIDGE_VLAN_TUNNEL_ID:
|
||||
tunnelId = native.Uint32(tunnelInfo.Value)
|
||||
case nl.IFLA_BRIDGE_VLAN_TUNNEL_VID:
|
||||
vid = native.Uint16(tunnelInfo.Value)
|
||||
case nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS:
|
||||
flag = native.Uint16(tunnelInfo.Value)
|
||||
}
|
||||
}
|
||||
|
||||
if flag == nl.BRIDGE_VLAN_INFO_RANGE_END {
|
||||
lastTi := results[len(results)-1]
|
||||
vni := lastTi.TunId + 1
|
||||
for i := lastTi.Vid + 1; i < vid; i++ {
|
||||
t := nl.TunnelInfo{
|
||||
TunId: vni,
|
||||
Vid: i,
|
||||
}
|
||||
results = append(results, t)
|
||||
vni++
|
||||
}
|
||||
}
|
||||
|
||||
t := nl.TunnelInfo{
|
||||
TunId: tunnelId,
|
||||
Vid: vid,
|
||||
}
|
||||
|
||||
results = append(results, t)
|
||||
return results, nil
|
||||
}
|
||||
|
||||
// BridgeVlanList gets a map of device id to bridge vlan infos.
|
||||
// Equivalent to: `bridge vlan show`
|
||||
//
|
||||
@@ -61,6 +152,38 @@ func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
|
||||
return ret, executeErr
|
||||
}
|
||||
|
||||
// BridgeVlanAddTunnelInfo adds a new vlan filter entry
|
||||
// Equivalent to: `bridge vlan add dev DEV vid VID tunnel_info id TUNID [ self ] [ master ]`
|
||||
func BridgeVlanAddTunnelInfo(link Link, vid uint16, tunid uint32, self, master bool) error {
|
||||
return pkgHandle.BridgeVlanAddTunnelInfo(link, vid, 0, tunid, 0, self, master)
|
||||
}
|
||||
|
||||
// BridgeVlanAddRangeTunnelInfoRange adds a new vlan filter entry
|
||||
// Equivalent to: `bridge vlan add dev DEV vid VID-VIDEND tunnel_info id VIN-VINEND [ self ] [ master ]`
|
||||
func BridgeVlanAddRangeTunnelInfoRange(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
|
||||
return pkgHandle.BridgeVlanAddTunnelInfo(link, vid, vidEnd, tunid, tunidEnd, self, master)
|
||||
}
|
||||
|
||||
func (h *Handle) BridgeVlanAddTunnelInfo(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
|
||||
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, vidEnd, tunid, tunidEnd, false, false, self, master)
|
||||
}
|
||||
|
||||
// BridgeVlanDelTunnelInfo adds a new vlan filter entry
|
||||
// Equivalent to: `bridge vlan del dev DEV vid VID tunnel_info id TUNID [ self ] [ master ]`
|
||||
func BridgeVlanDelTunnelInfo(link Link, vid uint16, tunid uint32, self, master bool) error {
|
||||
return pkgHandle.BridgeVlanDelTunnelInfo(link, vid, 0, tunid, 0, self, master)
|
||||
}
|
||||
|
||||
// BridgeVlanDelRangeTunnelInfoRange adds a new vlan filter entry
|
||||
// Equivalent to: `bridge vlan del dev DEV vid VID-VIDEND tunnel_info id VIN-VINEND [ self ] [ master ]`
|
||||
func BridgeVlanDelRangeTunnelInfoRange(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
|
||||
return pkgHandle.BridgeVlanDelTunnelInfo(link, vid, vidEnd, tunid, tunidEnd, self, master)
|
||||
}
|
||||
|
||||
func (h *Handle) BridgeVlanDelTunnelInfo(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
|
||||
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, vidEnd, tunid, tunidEnd, false, false, self, master)
|
||||
}
|
||||
|
||||
// BridgeVlanAdd adds a new vlan filter entry
|
||||
// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
|
||||
func BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error {
|
||||
@@ -70,7 +193,7 @@ func BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) err
|
||||
// BridgeVlanAdd adds a new vlan filter entry
|
||||
// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
|
||||
func (h *Handle) BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error {
|
||||
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, 0, pvid, untagged, self, master)
|
||||
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, 0, 0, 0, pvid, untagged, self, master)
|
||||
}
|
||||
|
||||
// BridgeVlanAddRange adds a new vlan filter entry
|
||||
@@ -82,7 +205,7 @@ func BridgeVlanAddRange(link Link, vid, vidEnd uint16, pvid, untagged, self, mas
|
||||
// BridgeVlanAddRange adds a new vlan filter entry
|
||||
// Equivalent to: `bridge vlan add dev DEV vid VID-VIDEND [ pvid ] [ untagged ] [ self ] [ master ]`
|
||||
func (h *Handle) BridgeVlanAddRange(link Link, vid, vidEnd uint16, pvid, untagged, self, master bool) error {
|
||||
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, vidEnd, pvid, untagged, self, master)
|
||||
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, vidEnd, 0, 0, pvid, untagged, self, master)
|
||||
}
|
||||
|
||||
// BridgeVlanDel adds a new vlan filter entry
|
||||
@@ -94,7 +217,7 @@ func BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) err
|
||||
// BridgeVlanDel adds a new vlan filter entry
|
||||
// Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
|
||||
func (h *Handle) BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) error {
|
||||
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, 0, pvid, untagged, self, master)
|
||||
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, 0, 0, 0, pvid, untagged, self, master)
|
||||
}
|
||||
|
||||
// BridgeVlanDelRange adds a new vlan filter entry
|
||||
@@ -106,10 +229,10 @@ func BridgeVlanDelRange(link Link, vid, vidEnd uint16, pvid, untagged, self, mas
|
||||
// BridgeVlanDelRange adds a new vlan filter entry
|
||||
// Equivalent to: `bridge vlan del dev DEV vid VID-VIDEND [ pvid ] [ untagged ] [ self ] [ master ]`
|
||||
func (h *Handle) BridgeVlanDelRange(link Link, vid, vidEnd uint16, pvid, untagged, self, master bool) error {
|
||||
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, vidEnd, pvid, untagged, self, master)
|
||||
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, vidEnd, 0, 0, pvid, untagged, self, master)
|
||||
}
|
||||
|
||||
func (h *Handle) bridgeVlanModify(cmd int, link Link, vid, vidEnd uint16, pvid, untagged, self, master bool) error {
|
||||
func (h *Handle) bridgeVlanModify(cmd int, link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, pvid, untagged, self, master bool) error {
|
||||
base := link.Attrs()
|
||||
h.ensureIndex(base)
|
||||
req := h.newNetlinkRequest(cmd, unix.NLM_F_ACK)
|
||||
@@ -129,25 +252,45 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid, vidEnd uint16, pvid,
|
||||
if flags > 0 {
|
||||
br.AddRtAttr(nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags))
|
||||
}
|
||||
vlanInfo := &nl.BridgeVlanInfo{Vid: vid}
|
||||
if pvid {
|
||||
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_PVID
|
||||
}
|
||||
if untagged {
|
||||
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED
|
||||
}
|
||||
|
||||
if vidEnd != 0 {
|
||||
vlanEndInfo := &nl.BridgeVlanInfo{Vid: vidEnd}
|
||||
vlanEndInfo.Flags = vlanInfo.Flags
|
||||
if tunid != 0 {
|
||||
if tunidEnd != 0 {
|
||||
tiStart := br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO, nil)
|
||||
tiStart.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_ID, nl.Uint32Attr(tunid))
|
||||
tiStart.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_VID, nl.Uint16Attr(vid))
|
||||
tiStart.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, nl.Uint16Attr(nl.BRIDGE_VLAN_INFO_RANGE_BEGIN))
|
||||
|
||||
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_BEGIN
|
||||
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
|
||||
tiEnd := br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO, nil)
|
||||
tiEnd.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_ID, nl.Uint32Attr(tunidEnd))
|
||||
tiEnd.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_VID, nl.Uint16Attr(vidEnd))
|
||||
tiEnd.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, nl.Uint16Attr(nl.BRIDGE_VLAN_INFO_RANGE_END))
|
||||
} else {
|
||||
ti := br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO, nil)
|
||||
ti.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_ID, nl.Uint32Attr(tunid))
|
||||
ti.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_VID, nl.Uint16Attr(vid))
|
||||
ti.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, nl.Uint16Attr(0))
|
||||
}
|
||||
} else {
|
||||
vlanInfo := &nl.BridgeVlanInfo{Vid: vid}
|
||||
if pvid {
|
||||
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_PVID
|
||||
}
|
||||
if untagged {
|
||||
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED
|
||||
}
|
||||
|
||||
vlanEndInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_END
|
||||
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanEndInfo.Serialize())
|
||||
} else {
|
||||
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
|
||||
if vidEnd != 0 {
|
||||
vlanEndInfo := &nl.BridgeVlanInfo{Vid: vidEnd}
|
||||
vlanEndInfo.Flags = vlanInfo.Flags
|
||||
|
||||
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_BEGIN
|
||||
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
|
||||
|
||||
vlanEndInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_END
|
||||
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanEndInfo.Serialize())
|
||||
} else {
|
||||
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
|
||||
}
|
||||
}
|
||||
|
||||
req.AddData(br)
|
||||
|
||||
@@ -79,6 +79,131 @@ func TestBridgeVlan(t *testing.T) {
|
||||
}
|
||||
}
|
||||
|
||||
func TestBridgeVlanTunnelInfo(t *testing.T) {
|
||||
minKernelRequired(t, 4, 11)
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
if err := remountSysfs(); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
bridgeName := "br0"
|
||||
vxlanName := "vxlan0"
|
||||
|
||||
// ip link add br0 type bridge
|
||||
bridge := &Bridge{LinkAttrs: LinkAttrs{Name: bridgeName}}
|
||||
if err := LinkAdd(bridge); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// ip link add vxlan0 type vxlan dstport 4789 nolearning external local 10.0.1.1
|
||||
vxlan := &Vxlan{
|
||||
// local
|
||||
SrcAddr: []byte("10.0.1.1"),
|
||||
Learning: false,
|
||||
// external
|
||||
FlowBased: true,
|
||||
// dstport
|
||||
Port: 4789,
|
||||
LinkAttrs: LinkAttrs{Name: vxlanName},
|
||||
}
|
||||
if err := LinkAdd(vxlan); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// ip link set dev vxlan0 master br0
|
||||
if err := LinkSetMaster(vxlan, bridge); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// ip link set br0 type bridge vlan_filtering 1
|
||||
if err := BridgeSetVlanFiltering(bridge, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// bridge link set dev vxlan0 vlan_tunnel on
|
||||
if err := LinkSetVlanTunnel(vxlan, true); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
p, err := LinkGetProtinfo(vxlan)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if !p.VlanTunnel {
|
||||
t.Fatal("vlan tunnel should be enabled on vxlan device")
|
||||
}
|
||||
|
||||
// bridge vlan add vid 10 dev vxlan0
|
||||
if err := BridgeVlanAdd(vxlan, 10, false, false, false, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// bridge vlan add vid 11 dev vxlan0
|
||||
if err := BridgeVlanAdd(vxlan, 11, false, false, false, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// bridge vlan add dev vxlan0 vid 10 tunnel_info id 20
|
||||
if err := BridgeVlanAddTunnelInfo(vxlan, 10, 20, false, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tis, err := BridgeVlanTunnelShow()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(tis) != 1 {
|
||||
t.Fatal("only one tunnel info")
|
||||
}
|
||||
ti := tis[0]
|
||||
if ti.TunId != 20 || ti.Vid != 10 {
|
||||
t.Fatal("unexpected result")
|
||||
}
|
||||
|
||||
// bridge vlan del dev vxlan0 vid 10 tunnel_info id 20
|
||||
if err := BridgeVlanDelTunnelInfo(vxlan, 10, 20, false, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tis, err = BridgeVlanTunnelShow()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(tis) != 0 {
|
||||
t.Fatal("tunnel info should have been deleted")
|
||||
}
|
||||
|
||||
// bridge vlan add dev vxlan0 vid 10-11 tunnel_info id 20-21
|
||||
if err := BridgeVlanAddRangeTunnelInfoRange(vxlan, 10, 11, 20, 21, false, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tis, err = BridgeVlanTunnelShow()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if len(tis) != 2 {
|
||||
t.Fatal("two tunnel info")
|
||||
}
|
||||
|
||||
// bridge vlan del dev vxlan0 vid 10-11 tunnel_info id 20-21
|
||||
if err := BridgeVlanDelRangeTunnelInfoRange(vxlan, 10, 11, 20, 21, false, false); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
tis, err = BridgeVlanTunnelShow()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if len(tis) != 0 {
|
||||
t.Fatal("tunnel info should have been deleted")
|
||||
}
|
||||
}
|
||||
|
||||
func TestBridgeGroupFwdMask(t *testing.T) {
|
||||
minKernelRequired(t, 4, 15) //minimal release for per-port group_fwd_mask
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
|
||||
@@ -2553,6 +2553,14 @@ func (h *Handle) LinkSetLearning(link Link, mode bool) error {
|
||||
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING)
|
||||
}
|
||||
|
||||
func LinkSetVlanTunnel(link Link, mode bool) error {
|
||||
return pkgHandle.LinkSetVlanTunnel(link, mode)
|
||||
}
|
||||
|
||||
func (h *Handle) LinkSetVlanTunnel(link Link, mode bool) error {
|
||||
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_VLAN_TUNNEL)
|
||||
}
|
||||
|
||||
func LinkSetRootBlock(link Link, mode bool) error {
|
||||
return pkgHandle.LinkSetRootBlock(link, mode)
|
||||
}
|
||||
|
||||
@@ -26,6 +26,14 @@ const (
|
||||
IFLA_BRIDGE_FLAGS = iota
|
||||
IFLA_BRIDGE_MODE
|
||||
IFLA_BRIDGE_VLAN_INFO
|
||||
IFLA_BRIDGE_VLAN_TUNNEL_INFO
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_BRIDGE_VLAN_TUNNEL_UNSPEC = iota
|
||||
IFLA_BRIDGE_VLAN_TUNNEL_ID
|
||||
IFLA_BRIDGE_VLAN_TUNNEL_VID
|
||||
IFLA_BRIDGE_VLAN_TUNNEL_FLAGS
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -41,6 +49,11 @@ const (
|
||||
// __u16 vid;
|
||||
// };
|
||||
|
||||
type TunnelInfo struct {
|
||||
TunId uint32
|
||||
Vid uint16
|
||||
}
|
||||
|
||||
type BridgeVlanInfo struct {
|
||||
Flags uint16
|
||||
Vid uint16
|
||||
|
||||
@@ -16,6 +16,7 @@ type Protinfo struct {
|
||||
ProxyArpWiFi bool
|
||||
Isolated bool
|
||||
NeighSuppress bool
|
||||
VlanTunnel bool
|
||||
}
|
||||
|
||||
// String returns a list of enabled flags
|
||||
@@ -55,6 +56,9 @@ func (prot *Protinfo) String() string {
|
||||
if prot.NeighSuppress {
|
||||
boolStrings = append(boolStrings, "NeighSuppress")
|
||||
}
|
||||
if prot.VlanTunnel {
|
||||
boolStrings = append(boolStrings, "VlanTunnel")
|
||||
}
|
||||
return strings.Join(boolStrings, " ")
|
||||
}
|
||||
|
||||
|
||||
@@ -77,7 +77,10 @@ func parseProtinfo(infos []syscall.NetlinkRouteAttr) (pi Protinfo) {
|
||||
pi.Isolated = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_NEIGH_SUPPRESS:
|
||||
pi.NeighSuppress = byteToBool(info.Value[0])
|
||||
case nl.IFLA_BRPORT_VLAN_TUNNEL:
|
||||
pi.VlanTunnel = byteToBool(info.Value[0])
|
||||
}
|
||||
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user