Skip to content

Commit 06c2c01

Browse files
zlavaaboch
authored andcommitted
feat: add vlanid - tunnelid mapping support
1 parent c4bb4f9 commit 06c2c01

File tree

6 files changed

+317
-21
lines changed

6 files changed

+317
-21
lines changed

bridge_linux.go

Lines changed: 164 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -3,11 +3,102 @@ package netlink
33
import (
44
"errors"
55
"fmt"
6+
"syscall"
67

78
"github.com/vishvananda/netlink/nl"
89
"golang.org/x/sys/unix"
910
)
1011

12+
// BridgeVlanTunnelShow gets vlanid-tunnelid mapping.
13+
// Equivalent to: `bridge vlan tunnelshow`
14+
//
15+
// If the returned error is [ErrDumpInterrupted], results may be inconsistent
16+
// or incomplete.
17+
func BridgeVlanTunnelShow() ([]nl.TunnelInfo, error) {
18+
return pkgHandle.BridgeVlanTunnelShow()
19+
}
20+
21+
func (h *Handle) BridgeVlanTunnelShow() ([]nl.TunnelInfo, error) {
22+
req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
23+
msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
24+
req.AddData(msg)
25+
req.AddData(nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
26+
27+
msgs, executeErr := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
28+
if executeErr != nil && !errors.Is(executeErr, ErrDumpInterrupted) {
29+
return nil, executeErr
30+
}
31+
ret := make([]nl.TunnelInfo, 0)
32+
for _, m := range msgs {
33+
msg := nl.DeserializeIfInfomsg(m)
34+
35+
attrs, err := nl.ParseRouteAttr(m[msg.Len():])
36+
if err != nil {
37+
return nil, err
38+
}
39+
for _, attr := range attrs {
40+
switch attr.Attr.Type {
41+
case unix.IFLA_AF_SPEC:
42+
nestedAttrs, err := nl.ParseRouteAttr(attr.Value)
43+
if err != nil {
44+
return nil, fmt.Errorf("failed to parse nested attr %v", err)
45+
}
46+
for _, nestAttr := range nestedAttrs {
47+
switch nestAttr.Attr.Type {
48+
case nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO:
49+
ret, err = parseTunnelInfo(&nestAttr, ret)
50+
if err != nil {
51+
return nil, fmt.Errorf("failed to parse tunnelinfo %v", err)
52+
}
53+
}
54+
}
55+
}
56+
}
57+
}
58+
return ret, executeErr
59+
}
60+
61+
func parseTunnelInfo(nestAttr *syscall.NetlinkRouteAttr, results []nl.TunnelInfo) ([]nl.TunnelInfo, error) {
62+
tunnelInfos, err := nl.ParseRouteAttr(nestAttr.Value)
63+
if err != nil {
64+
return nil, fmt.Errorf("failed to parse nested attr %v", err)
65+
}
66+
var tunnelId uint32
67+
var vid uint16
68+
var flag uint16
69+
for _, tunnelInfo := range tunnelInfos {
70+
switch tunnelInfo.Attr.Type {
71+
case nl.IFLA_BRIDGE_VLAN_TUNNEL_ID:
72+
tunnelId = native.Uint32(tunnelInfo.Value)
73+
case nl.IFLA_BRIDGE_VLAN_TUNNEL_VID:
74+
vid = native.Uint16(tunnelInfo.Value)
75+
case nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS:
76+
flag = native.Uint16(tunnelInfo.Value)
77+
}
78+
}
79+
80+
if flag == nl.BRIDGE_VLAN_INFO_RANGE_END {
81+
lastTi := results[len(results)-1]
82+
vni := lastTi.TunId + 1
83+
for i := lastTi.Vid + 1; i < vid; i++ {
84+
t := nl.TunnelInfo{
85+
TunId: vni,
86+
Vid: i,
87+
}
88+
results = append(results, t)
89+
vni++
90+
}
91+
}
92+
93+
t := nl.TunnelInfo{
94+
TunId: tunnelId,
95+
Vid: vid,
96+
}
97+
98+
results = append(results, t)
99+
return results, nil
100+
}
101+
11102
// BridgeVlanList gets a map of device id to bridge vlan infos.
12103
// Equivalent to: `bridge vlan show`
13104
//
@@ -61,6 +152,38 @@ func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
61152
return ret, executeErr
62153
}
63154

155+
// BridgeVlanAddTunnelInfo adds a new vlan filter entry
156+
// Equivalent to: `bridge vlan add dev DEV vid VID tunnel_info id TUNID [ self ] [ master ]`
157+
func BridgeVlanAddTunnelInfo(link Link, vid uint16, tunid uint32, self, master bool) error {
158+
return pkgHandle.BridgeVlanAddTunnelInfo(link, vid, 0, tunid, 0, self, master)
159+
}
160+
161+
// BridgeVlanAddRangeTunnelInfoRange adds a new vlan filter entry
162+
// Equivalent to: `bridge vlan add dev DEV vid VID-VIDEND tunnel_info id VIN-VINEND [ self ] [ master ]`
163+
func BridgeVlanAddRangeTunnelInfoRange(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
164+
return pkgHandle.BridgeVlanAddTunnelInfo(link, vid, vidEnd, tunid, tunidEnd, self, master)
165+
}
166+
167+
func (h *Handle) BridgeVlanAddTunnelInfo(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
168+
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, vidEnd, tunid, tunidEnd, false, false, self, master)
169+
}
170+
171+
// BridgeVlanDelTunnelInfo adds a new vlan filter entry
172+
// Equivalent to: `bridge vlan del dev DEV vid VID tunnel_info id TUNID [ self ] [ master ]`
173+
func BridgeVlanDelTunnelInfo(link Link, vid uint16, tunid uint32, self, master bool) error {
174+
return pkgHandle.BridgeVlanDelTunnelInfo(link, vid, 0, tunid, 0, self, master)
175+
}
176+
177+
// BridgeVlanDelRangeTunnelInfoRange adds a new vlan filter entry
178+
// Equivalent to: `bridge vlan del dev DEV vid VID-VIDEND tunnel_info id VIN-VINEND [ self ] [ master ]`
179+
func BridgeVlanDelRangeTunnelInfoRange(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
180+
return pkgHandle.BridgeVlanDelTunnelInfo(link, vid, vidEnd, tunid, tunidEnd, self, master)
181+
}
182+
183+
func (h *Handle) BridgeVlanDelTunnelInfo(link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, self, master bool) error {
184+
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, vidEnd, tunid, tunidEnd, false, false, self, master)
185+
}
186+
64187
// BridgeVlanAdd adds a new vlan filter entry
65188
// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
66189
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
70193
// BridgeVlanAdd adds a new vlan filter entry
71194
// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
72195
func (h *Handle) BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error {
73-
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, 0, pvid, untagged, self, master)
196+
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, 0, 0, 0, pvid, untagged, self, master)
74197
}
75198

76199
// BridgeVlanAddRange adds a new vlan filter entry
@@ -82,7 +205,7 @@ func BridgeVlanAddRange(link Link, vid, vidEnd uint16, pvid, untagged, self, mas
82205
// BridgeVlanAddRange adds a new vlan filter entry
83206
// Equivalent to: `bridge vlan add dev DEV vid VID-VIDEND [ pvid ] [ untagged ] [ self ] [ master ]`
84207
func (h *Handle) BridgeVlanAddRange(link Link, vid, vidEnd uint16, pvid, untagged, self, master bool) error {
85-
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, vidEnd, pvid, untagged, self, master)
208+
return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, vidEnd, 0, 0, pvid, untagged, self, master)
86209
}
87210

88211
// BridgeVlanDel adds a new vlan filter entry
@@ -94,7 +217,7 @@ func BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) err
94217
// BridgeVlanDel adds a new vlan filter entry
95218
// Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
96219
func (h *Handle) BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) error {
97-
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, 0, pvid, untagged, self, master)
220+
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, 0, 0, 0, pvid, untagged, self, master)
98221
}
99222

100223
// BridgeVlanDelRange adds a new vlan filter entry
@@ -106,10 +229,10 @@ func BridgeVlanDelRange(link Link, vid, vidEnd uint16, pvid, untagged, self, mas
106229
// BridgeVlanDelRange adds a new vlan filter entry
107230
// Equivalent to: `bridge vlan del dev DEV vid VID-VIDEND [ pvid ] [ untagged ] [ self ] [ master ]`
108231
func (h *Handle) BridgeVlanDelRange(link Link, vid, vidEnd uint16, pvid, untagged, self, master bool) error {
109-
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, vidEnd, pvid, untagged, self, master)
232+
return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, vidEnd, 0, 0, pvid, untagged, self, master)
110233
}
111234

112-
func (h *Handle) bridgeVlanModify(cmd int, link Link, vid, vidEnd uint16, pvid, untagged, self, master bool) error {
235+
func (h *Handle) bridgeVlanModify(cmd int, link Link, vid, vidEnd uint16, tunid, tunidEnd uint32, pvid, untagged, self, master bool) error {
113236
base := link.Attrs()
114237
h.ensureIndex(base)
115238
req := h.newNetlinkRequest(cmd, unix.NLM_F_ACK)
@@ -129,25 +252,45 @@ func (h *Handle) bridgeVlanModify(cmd int, link Link, vid, vidEnd uint16, pvid,
129252
if flags > 0 {
130253
br.AddRtAttr(nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags))
131254
}
132-
vlanInfo := &nl.BridgeVlanInfo{Vid: vid}
133-
if pvid {
134-
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_PVID
135-
}
136-
if untagged {
137-
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED
138-
}
139255

140-
if vidEnd != 0 {
141-
vlanEndInfo := &nl.BridgeVlanInfo{Vid: vidEnd}
142-
vlanEndInfo.Flags = vlanInfo.Flags
256+
if tunid != 0 {
257+
if tunidEnd != 0 {
258+
tiStart := br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO, nil)
259+
tiStart.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_ID, nl.Uint32Attr(tunid))
260+
tiStart.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_VID, nl.Uint16Attr(vid))
261+
tiStart.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, nl.Uint16Attr(nl.BRIDGE_VLAN_INFO_RANGE_BEGIN))
262+
263+
tiEnd := br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO, nil)
264+
tiEnd.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_ID, nl.Uint32Attr(tunidEnd))
265+
tiEnd.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_VID, nl.Uint16Attr(vidEnd))
266+
tiEnd.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, nl.Uint16Attr(nl.BRIDGE_VLAN_INFO_RANGE_END))
267+
} else {
268+
ti := br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_INFO, nil)
269+
ti.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_ID, nl.Uint32Attr(tunid))
270+
ti.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_VID, nl.Uint16Attr(vid))
271+
ti.AddRtAttr(nl.IFLA_BRIDGE_VLAN_TUNNEL_FLAGS, nl.Uint16Attr(0))
272+
}
273+
} else {
274+
vlanInfo := &nl.BridgeVlanInfo{Vid: vid}
275+
if pvid {
276+
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_PVID
277+
}
278+
if untagged {
279+
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED
280+
}
281+
282+
if vidEnd != 0 {
283+
vlanEndInfo := &nl.BridgeVlanInfo{Vid: vidEnd}
284+
vlanEndInfo.Flags = vlanInfo.Flags
143285

144-
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_BEGIN
145-
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
286+
vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_BEGIN
287+
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
146288

147-
vlanEndInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_END
148-
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanEndInfo.Serialize())
149-
} else {
150-
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
289+
vlanEndInfo.Flags |= nl.BRIDGE_VLAN_INFO_RANGE_END
290+
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanEndInfo.Serialize())
291+
} else {
292+
br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
293+
}
151294
}
152295

153296
req.AddData(br)

bridge_linux_test.go

Lines changed: 125 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,131 @@ func TestBridgeVlan(t *testing.T) {
7979
}
8080
}
8181

82+
func TestBridgeVlanTunnelInfo(t *testing.T) {
83+
minKernelRequired(t, 4, 11)
84+
tearDown := setUpNetlinkTest(t)
85+
defer tearDown()
86+
87+
if err := remountSysfs(); err != nil {
88+
t.Fatal(err)
89+
}
90+
bridgeName := "br0"
91+
vxlanName := "vxlan0"
92+
93+
// ip link add br0 type bridge
94+
bridge := &Bridge{LinkAttrs: LinkAttrs{Name: bridgeName}}
95+
if err := LinkAdd(bridge); err != nil {
96+
t.Fatal(err)
97+
}
98+
99+
// ip link add vxlan0 type vxlan dstport 4789 nolearning external local 10.0.1.1
100+
vxlan := &Vxlan{
101+
// local
102+
SrcAddr: []byte("10.0.1.1"),
103+
Learning: false,
104+
// external
105+
FlowBased: true,
106+
// dstport
107+
Port: 4789,
108+
LinkAttrs: LinkAttrs{Name: vxlanName},
109+
}
110+
if err := LinkAdd(vxlan); err != nil {
111+
t.Fatal(err)
112+
}
113+
114+
// ip link set dev vxlan0 master br0
115+
if err := LinkSetMaster(vxlan, bridge); err != nil {
116+
t.Fatal(err)
117+
}
118+
119+
// ip link set br0 type bridge vlan_filtering 1
120+
if err := BridgeSetVlanFiltering(bridge, true); err != nil {
121+
t.Fatal(err)
122+
}
123+
124+
// bridge link set dev vxlan0 vlan_tunnel on
125+
if err := LinkSetVlanTunnel(vxlan, true); err != nil {
126+
t.Fatal(err)
127+
}
128+
129+
p, err := LinkGetProtinfo(vxlan)
130+
if err != nil {
131+
t.Fatal(err)
132+
}
133+
if !p.VlanTunnel {
134+
t.Fatal("vlan tunnel should be enabled on vxlan device")
135+
}
136+
137+
// bridge vlan add vid 10 dev vxlan0
138+
if err := BridgeVlanAdd(vxlan, 10, false, false, false, false); err != nil {
139+
t.Fatal(err)
140+
}
141+
142+
// bridge vlan add vid 11 dev vxlan0
143+
if err := BridgeVlanAdd(vxlan, 11, false, false, false, false); err != nil {
144+
t.Fatal(err)
145+
}
146+
147+
// bridge vlan add dev vxlan0 vid 10 tunnel_info id 20
148+
if err := BridgeVlanAddTunnelInfo(vxlan, 10, 20, false, false); err != nil {
149+
t.Fatal(err)
150+
}
151+
152+
tis, err := BridgeVlanTunnelShow()
153+
if err != nil {
154+
t.Fatal(err)
155+
}
156+
157+
if len(tis) != 1 {
158+
t.Fatal("only one tunnel info")
159+
}
160+
ti := tis[0]
161+
if ti.TunId != 20 || ti.Vid != 10 {
162+
t.Fatal("unexpected result")
163+
}
164+
165+
// bridge vlan del dev vxlan0 vid 10 tunnel_info id 20
166+
if err := BridgeVlanDelTunnelInfo(vxlan, 10, 20, false, false); err != nil {
167+
t.Fatal(err)
168+
}
169+
170+
tis, err = BridgeVlanTunnelShow()
171+
if err != nil {
172+
t.Fatal(err)
173+
}
174+
175+
if len(tis) != 0 {
176+
t.Fatal("tunnel info should have been deleted")
177+
}
178+
179+
// bridge vlan add dev vxlan0 vid 10-11 tunnel_info id 20-21
180+
if err := BridgeVlanAddRangeTunnelInfoRange(vxlan, 10, 11, 20, 21, false, false); err != nil {
181+
t.Fatal(err)
182+
}
183+
184+
tis, err = BridgeVlanTunnelShow()
185+
if err != nil {
186+
t.Fatal(err)
187+
}
188+
if len(tis) != 2 {
189+
t.Fatal("two tunnel info")
190+
}
191+
192+
// bridge vlan del dev vxlan0 vid 10-11 tunnel_info id 20-21
193+
if err := BridgeVlanDelRangeTunnelInfoRange(vxlan, 10, 11, 20, 21, false, false); err != nil {
194+
t.Fatal(err)
195+
}
196+
197+
tis, err = BridgeVlanTunnelShow()
198+
if err != nil {
199+
t.Fatal(err)
200+
}
201+
202+
if len(tis) != 0 {
203+
t.Fatal("tunnel info should have been deleted")
204+
}
205+
}
206+
82207
func TestBridgeGroupFwdMask(t *testing.T) {
83208
minKernelRequired(t, 4, 15) //minimal release for per-port group_fwd_mask
84209
tearDown := setUpNetlinkTest(t)

link_linux.go

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2553,6 +2553,14 @@ func (h *Handle) LinkSetLearning(link Link, mode bool) error {
25532553
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_LEARNING)
25542554
}
25552555

2556+
func LinkSetVlanTunnel(link Link, mode bool) error {
2557+
return pkgHandle.LinkSetVlanTunnel(link, mode)
2558+
}
2559+
2560+
func (h *Handle) LinkSetVlanTunnel(link Link, mode bool) error {
2561+
return h.setProtinfoAttr(link, mode, nl.IFLA_BRPORT_VLAN_TUNNEL)
2562+
}
2563+
25562564
func LinkSetRootBlock(link Link, mode bool) error {
25572565
return pkgHandle.LinkSetRootBlock(link, mode)
25582566
}

0 commit comments

Comments
 (0)