1package netlink
2
3import (
4	"fmt"
5
6	"github.com/vishvananda/netlink/nl"
7	"golang.org/x/sys/unix"
8)
9
10// BridgeVlanList gets a map of device id to bridge vlan infos.
11// Equivalent to: `bridge vlan show`
12func BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
13	return pkgHandle.BridgeVlanList()
14}
15
16// BridgeVlanList gets a map of device id to bridge vlan infos.
17// Equivalent to: `bridge vlan show`
18func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) {
19	req := h.newNetlinkRequest(unix.RTM_GETLINK, unix.NLM_F_DUMP)
20	msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
21	req.AddData(msg)
22	req.AddData(nl.NewRtAttr(unix.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN))))
23
24	msgs, err := req.Execute(unix.NETLINK_ROUTE, unix.RTM_NEWLINK)
25	if err != nil {
26		return nil, err
27	}
28	ret := make(map[int32][]*nl.BridgeVlanInfo)
29	for _, m := range msgs {
30		msg := nl.DeserializeIfInfomsg(m)
31
32		attrs, err := nl.ParseRouteAttr(m[msg.Len():])
33		if err != nil {
34			return nil, err
35		}
36		for _, attr := range attrs {
37			switch attr.Attr.Type {
38			case unix.IFLA_AF_SPEC:
39				//nested attr
40				nestAttrs, err := nl.ParseRouteAttr(attr.Value)
41				if err != nil {
42					return nil, fmt.Errorf("failed to parse nested attr %v", err)
43				}
44				for _, nestAttr := range nestAttrs {
45					switch nestAttr.Attr.Type {
46					case nl.IFLA_BRIDGE_VLAN_INFO:
47						vlanInfo := nl.DeserializeBridgeVlanInfo(nestAttr.Value)
48						ret[msg.Index] = append(ret[msg.Index], vlanInfo)
49					}
50				}
51			}
52		}
53	}
54	return ret, nil
55}
56
57// BridgeVlanAdd adds a new vlan filter entry
58// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
59func BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error {
60	return pkgHandle.BridgeVlanAdd(link, vid, pvid, untagged, self, master)
61}
62
63// BridgeVlanAdd adds a new vlan filter entry
64// Equivalent to: `bridge vlan add dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
65func (h *Handle) BridgeVlanAdd(link Link, vid uint16, pvid, untagged, self, master bool) error {
66	return h.bridgeVlanModify(unix.RTM_SETLINK, link, vid, pvid, untagged, self, master)
67}
68
69// BridgeVlanDel adds a new vlan filter entry
70// Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
71func BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) error {
72	return pkgHandle.BridgeVlanDel(link, vid, pvid, untagged, self, master)
73}
74
75// BridgeVlanDel adds a new vlan filter entry
76// Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]`
77func (h *Handle) BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) error {
78	return h.bridgeVlanModify(unix.RTM_DELLINK, link, vid, pvid, untagged, self, master)
79}
80
81func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged, self, master bool) error {
82	base := link.Attrs()
83	h.ensureIndex(base)
84	req := h.newNetlinkRequest(cmd, unix.NLM_F_ACK)
85
86	msg := nl.NewIfInfomsg(unix.AF_BRIDGE)
87	msg.Index = int32(base.Index)
88	req.AddData(msg)
89
90	br := nl.NewRtAttr(unix.IFLA_AF_SPEC, nil)
91	var flags uint16
92	if self {
93		flags |= nl.BRIDGE_FLAGS_SELF
94	}
95	if master {
96		flags |= nl.BRIDGE_FLAGS_MASTER
97	}
98	if flags > 0 {
99		br.AddRtAttr(nl.IFLA_BRIDGE_FLAGS, nl.Uint16Attr(flags))
100	}
101	vlanInfo := &nl.BridgeVlanInfo{Vid: vid}
102	if pvid {
103		vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_PVID
104	}
105	if untagged {
106		vlanInfo.Flags |= nl.BRIDGE_VLAN_INFO_UNTAGGED
107	}
108	br.AddRtAttr(nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize())
109	req.AddData(br)
110	_, err := req.Execute(unix.NETLINK_ROUTE, 0)
111	return err
112}
113