package netlink import ( "fmt" "syscall" "github.com/vishvananda/netlink/nl" ) // BridgeVlanList gets a map of device id to bridge vlan infos. // Equivalent to: `bridge vlan show` func BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) { return pkgHandle.BridgeVlanList() } // BridgeVlanList gets a map of device id to bridge vlan infos. // Equivalent to: `bridge vlan show` func (h *Handle) BridgeVlanList() (map[int32][]*nl.BridgeVlanInfo, error) { req := h.newNetlinkRequest(syscall.RTM_GETLINK, syscall.NLM_F_DUMP) msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) req.AddData(msg) req.AddData(nl.NewRtAttr(nl.IFLA_EXT_MASK, nl.Uint32Attr(uint32(nl.RTEXT_FILTER_BRVLAN)))) msgs, err := req.Execute(syscall.NETLINK_ROUTE, syscall.RTM_NEWLINK) if err != nil { return nil, err } ret := make(map[int32][]*nl.BridgeVlanInfo) 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 nl.IFLA_AF_SPEC: //nested attr nestAttrs, err := nl.ParseRouteAttr(attr.Value) if err != nil { return nil, fmt.Errorf("failed to parse nested attr %v", err) } for _, nestAttr := range nestAttrs { switch nestAttr.Attr.Type { case nl.IFLA_BRIDGE_VLAN_INFO: vlanInfo := nl.DeserializeBridgeVlanInfo(nestAttr.Value) ret[msg.Index] = append(ret[msg.Index], vlanInfo) } } } } } return ret, nil } // 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 { return pkgHandle.BridgeVlanAdd(link, vid, pvid, untagged, self, master) } // 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(syscall.RTM_SETLINK, link, vid, pvid, untagged, self, master) } // BridgeVlanDel adds a new vlan filter entry // Equivalent to: `bridge vlan del dev DEV vid VID [ pvid ] [ untagged ] [ self ] [ master ]` func BridgeVlanDel(link Link, vid uint16, pvid, untagged, self, master bool) error { return pkgHandle.BridgeVlanDel(link, vid, pvid, untagged, self, master) } // 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(syscall.RTM_DELLINK, link, vid, pvid, untagged, self, master) } func (h *Handle) bridgeVlanModify(cmd int, link Link, vid uint16, pvid, untagged, self, master bool) error { base := link.Attrs() h.ensureIndex(base) req := h.newNetlinkRequest(cmd, syscall.NLM_F_ACK) msg := nl.NewIfInfomsg(syscall.AF_BRIDGE) msg.Index = int32(base.Index) req.AddData(msg) br := nl.NewRtAttr(nl.IFLA_AF_SPEC, nil) var flags uint16 if self { flags |= nl.BRIDGE_FLAGS_SELF } if master { flags |= nl.BRIDGE_FLAGS_MASTER } if flags > 0 { nl.NewRtAttrChild(br, 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 } nl.NewRtAttrChild(br, nl.IFLA_BRIDGE_VLAN_INFO, vlanInfo.Serialize()) req.AddData(br) _, err := req.Execute(syscall.NETLINK_ROUTE, 0) if err != nil { return err } return nil }