mirror of
https://github.com/vishvananda/netlink.git
synced 2025-09-26 20:01:13 +08:00
vlan: add support for flags and qos maps
Signed-off-by: Gwendolyn <me@gwendolyn.dev>
This commit is contained in:

committed by
Alessandro Boch

parent
b929916209
commit
17daef607c
11
link.go
11
link.go
@@ -290,8 +290,15 @@ func (bridge *Bridge) Type() string {
|
||||
// Vlan links have ParentIndex set in their Attrs()
|
||||
type Vlan struct {
|
||||
LinkAttrs
|
||||
VlanId int
|
||||
VlanProtocol VlanProtocol
|
||||
VlanId int
|
||||
VlanProtocol VlanProtocol
|
||||
IngressQosMap map[uint32]uint32
|
||||
EgressQosMap map[uint32]uint32
|
||||
ReorderHdr *bool
|
||||
Gvrp *bool
|
||||
LooseBinding *bool
|
||||
Mvrp *bool
|
||||
BridgeBinding *bool
|
||||
}
|
||||
|
||||
func (vlan *Vlan) Attrs() *LinkAttrs {
|
||||
|
120
link_linux.go
120
link_linux.go
@@ -1683,6 +1683,73 @@ func (h *Handle) linkModify(link Link, flags int) error {
|
||||
native.PutUint16(b, uint16(link.VlanId))
|
||||
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
|
||||
data.AddRtAttr(nl.IFLA_VLAN_ID, b)
|
||||
var vlanFlags uint32
|
||||
var vlanFlagsMask uint32
|
||||
if link.ReorderHdr != nil {
|
||||
vlanFlagsMask |= nl.VLAN_FLAG_REORDER_HDR
|
||||
if *link.ReorderHdr {
|
||||
vlanFlags |= nl.VLAN_FLAG_REORDER_HDR
|
||||
} else {
|
||||
vlanFlags &= ^uint32(nl.VLAN_FLAG_REORDER_HDR)
|
||||
}
|
||||
}
|
||||
if link.Gvrp != nil {
|
||||
vlanFlagsMask |= nl.VLAN_FLAG_GVRP
|
||||
if *link.Gvrp {
|
||||
vlanFlags |= nl.VLAN_FLAG_GVRP
|
||||
} else {
|
||||
vlanFlags &= ^uint32(nl.VLAN_FLAG_GVRP)
|
||||
}
|
||||
}
|
||||
if link.Mvrp != nil {
|
||||
vlanFlagsMask |= nl.VLAN_FLAG_MVRP
|
||||
if *link.Mvrp {
|
||||
vlanFlags |= nl.VLAN_FLAG_MVRP
|
||||
} else {
|
||||
vlanFlags &= ^uint32(nl.VLAN_FLAG_MVRP)
|
||||
}
|
||||
}
|
||||
if link.LooseBinding != nil {
|
||||
vlanFlagsMask |= nl.VLAN_FLAG_LOOSE_BINDING
|
||||
if *link.LooseBinding {
|
||||
vlanFlags |= nl.VLAN_FLAG_LOOSE_BINDING
|
||||
} else {
|
||||
vlanFlags &= ^uint32(nl.VLAN_FLAG_LOOSE_BINDING)
|
||||
}
|
||||
}
|
||||
if link.BridgeBinding != nil {
|
||||
vlanFlagsMask |= nl.VLAN_FLAG_BRIDGE_BINDING
|
||||
if *link.BridgeBinding {
|
||||
vlanFlags |= nl.VLAN_FLAG_BRIDGE_BINDING
|
||||
} else {
|
||||
vlanFlags &= ^uint32(nl.VLAN_FLAG_BRIDGE_BINDING)
|
||||
}
|
||||
}
|
||||
|
||||
buf := &bytes.Buffer{}
|
||||
buf.Write(nl.Uint32Attr(vlanFlags))
|
||||
buf.Write(nl.Uint32Attr(vlanFlagsMask))
|
||||
data.AddRtAttr(nl.IFLA_VLAN_FLAGS, buf.Bytes())
|
||||
|
||||
if link.IngressQosMap != nil {
|
||||
ingressMap := data.AddRtAttr(nl.IFLA_VLAN_INGRESS_QOS, nil)
|
||||
for from, to := range link.IngressQosMap {
|
||||
buf := &bytes.Buffer{}
|
||||
buf.Write(nl.Uint32Attr(from))
|
||||
buf.Write(nl.Uint32Attr(to))
|
||||
ingressMap.AddRtAttr(nl.IFLA_VLAN_QOS_MAPPING, buf.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
if link.EgressQosMap != nil {
|
||||
egressMap := data.AddRtAttr(nl.IFLA_VLAN_EGRESS_QOS, nil)
|
||||
for from, to := range link.EgressQosMap {
|
||||
buf := &bytes.Buffer{}
|
||||
buf.Write(nl.Uint32Attr(from))
|
||||
buf.Write(nl.Uint32Attr(to))
|
||||
egressMap.AddRtAttr(nl.IFLA_VLAN_QOS_MAPPING, buf.Bytes())
|
||||
}
|
||||
}
|
||||
|
||||
if link.VlanProtocol != VLAN_PROTOCOL_UNKNOWN {
|
||||
data.AddRtAttr(nl.IFLA_VLAN_PROTOCOL, htons(uint16(link.VlanProtocol)))
|
||||
@@ -2801,12 +2868,65 @@ func parseNetkitData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
}
|
||||
}
|
||||
|
||||
func parseVlanQosMap(data []byte) map[uint32]uint32 {
|
||||
values, err := nl.ParseRouteAttr(data)
|
||||
if err != nil {
|
||||
return nil
|
||||
}
|
||||
|
||||
qosMap := make(map[uint32]uint32)
|
||||
|
||||
for _, value := range values {
|
||||
switch value.Attr.Type {
|
||||
case nl.IFLA_VLAN_QOS_MAPPING:
|
||||
from := native.Uint32(value.Value[:4])
|
||||
to := native.Uint32(value.Value[4:])
|
||||
qosMap[from] = to
|
||||
}
|
||||
}
|
||||
|
||||
return qosMap
|
||||
}
|
||||
|
||||
func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||
vlan := link.(*Vlan)
|
||||
for _, datum := range data {
|
||||
switch datum.Attr.Type {
|
||||
case nl.IFLA_VLAN_ID:
|
||||
vlan.VlanId = int(native.Uint16(datum.Value[0:2]))
|
||||
case nl.IFLA_VLAN_FLAGS:
|
||||
flags := native.Uint32(datum.Value[0:4])
|
||||
trueVal := true
|
||||
falseVal := false
|
||||
if flags&nl.VLAN_FLAG_REORDER_HDR != 0 {
|
||||
vlan.ReorderHdr = &trueVal
|
||||
} else {
|
||||
vlan.ReorderHdr = &falseVal
|
||||
}
|
||||
if flags&nl.VLAN_FLAG_GVRP != 0 {
|
||||
vlan.Gvrp = &trueVal
|
||||
} else {
|
||||
vlan.Gvrp = &falseVal
|
||||
}
|
||||
if flags&nl.VLAN_FLAG_LOOSE_BINDING != 0 {
|
||||
vlan.LooseBinding = &trueVal
|
||||
} else {
|
||||
vlan.LooseBinding = &falseVal
|
||||
}
|
||||
if flags&nl.VLAN_FLAG_MVRP != 0 {
|
||||
vlan.Mvrp = &trueVal
|
||||
} else {
|
||||
vlan.Mvrp = &falseVal
|
||||
}
|
||||
if flags&nl.VLAN_FLAG_BRIDGE_BINDING != 0 {
|
||||
vlan.BridgeBinding = &trueVal
|
||||
} else {
|
||||
vlan.BridgeBinding = &falseVal
|
||||
}
|
||||
case nl.IFLA_VLAN_EGRESS_QOS:
|
||||
vlan.EgressQosMap = parseVlanQosMap(datum.Value)
|
||||
case nl.IFLA_VLAN_INGRESS_QOS:
|
||||
vlan.IngressQosMap = parseVlanQosMap(datum.Value)
|
||||
case nl.IFLA_VLAN_PROTOCOL:
|
||||
vlan.VlanProtocol = VlanProtocol(int(ntohs(datum.Value[0:2])))
|
||||
}
|
||||
|
168
link_test.go
168
link_test.go
@@ -10,6 +10,7 @@ import (
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"reflect"
|
||||
"sort"
|
||||
"strings"
|
||||
"syscall"
|
||||
@@ -919,13 +920,178 @@ func TestLinkAddDelVlan(t *testing.T) {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
testLinkAddDel(t, &Vlan{LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index}, 900, VLAN_PROTOCOL_8021Q})
|
||||
testLinkAddDel(t, &Vlan{
|
||||
LinkAttrs: LinkAttrs{
|
||||
Name: "bar",
|
||||
ParentIndex: parent.Attrs().Index,
|
||||
},
|
||||
VlanId: 900,
|
||||
VlanProtocol: VLAN_PROTOCOL_8021Q,
|
||||
})
|
||||
|
||||
if err := LinkDel(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddVlanWithQosMaps(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
parent := &Dummy{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
ingressMap := map[uint32]uint32{
|
||||
0: 2,
|
||||
1: 3,
|
||||
2: 5,
|
||||
}
|
||||
|
||||
egressMap := map[uint32]uint32{
|
||||
1: 3,
|
||||
2: 5,
|
||||
3: 7,
|
||||
}
|
||||
|
||||
vlan := &Vlan{
|
||||
LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
|
||||
VlanId: 900,
|
||||
VlanProtocol: VLAN_PROTOCOL_8021Q,
|
||||
IngressQosMap: ingressMap,
|
||||
EgressQosMap: egressMap,
|
||||
}
|
||||
if err := LinkAdd(vlan); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
link, err := LinkByName("bar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if vlan, ok := link.(*Vlan); !ok {
|
||||
t.Fatalf("unexpected link type: %T", link)
|
||||
} else {
|
||||
if !reflect.DeepEqual(vlan.IngressQosMap, ingressMap) {
|
||||
t.Fatalf("expected ingress qos map to be %v, got %v", ingressMap, vlan.IngressQosMap)
|
||||
}
|
||||
if !reflect.DeepEqual(vlan.EgressQosMap, egressMap) {
|
||||
t.Fatalf("expected egress qos map to be %v, got %v", egressMap, vlan.EgressQosMap)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddVlanWithFlags(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
parent := &Dummy{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
valueTrue := true
|
||||
valueFalse := false
|
||||
vlan := &Vlan{
|
||||
LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
|
||||
VlanId: 900,
|
||||
VlanProtocol: VLAN_PROTOCOL_8021Q,
|
||||
Gvrp: &valueTrue,
|
||||
Mvrp: &valueFalse,
|
||||
BridgeBinding: &valueFalse,
|
||||
LooseBinding: &valueFalse,
|
||||
ReorderHdr: &valueTrue,
|
||||
}
|
||||
if err := LinkAdd(vlan); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
link, err := LinkByName("bar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if vlan, ok := link.(*Vlan); !ok {
|
||||
t.Fatalf("unexpected link type: %T", link)
|
||||
} else {
|
||||
if vlan.Gvrp == nil || *vlan.Gvrp != true {
|
||||
t.Fatalf("expected gvrp to be true, got %v", vlan.Gvrp)
|
||||
}
|
||||
if vlan.Mvrp == nil || *vlan.Mvrp != false {
|
||||
t.Fatalf("expected mvrp to be false, got %v", vlan.Mvrp)
|
||||
}
|
||||
if vlan.BridgeBinding == nil || *vlan.BridgeBinding != false {
|
||||
t.Fatalf("expected bridge binding to be false, got %v", vlan.BridgeBinding)
|
||||
}
|
||||
if vlan.LooseBinding == nil || *vlan.LooseBinding != false {
|
||||
t.Fatalf("expected loose binding to be false, got %v", vlan.LooseBinding)
|
||||
}
|
||||
if vlan.ReorderHdr == nil || *vlan.ReorderHdr != true {
|
||||
t.Fatalf("expected reorder hdr to be true, got %v", vlan.ReorderHdr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkModifyVlanFlags(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
||||
parent := &Dummy{LinkAttrs{Name: "foo"}}
|
||||
if err := LinkAdd(parent); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
valueTrue := true
|
||||
valueFalse := false
|
||||
vlan := &Vlan{
|
||||
LinkAttrs: LinkAttrs{Name: "bar", ParentIndex: parent.Attrs().Index},
|
||||
VlanId: 900,
|
||||
VlanProtocol: VLAN_PROTOCOL_8021Q,
|
||||
Gvrp: &valueTrue,
|
||||
Mvrp: &valueFalse,
|
||||
BridgeBinding: &valueFalse,
|
||||
LooseBinding: &valueFalse,
|
||||
ReorderHdr: &valueTrue,
|
||||
}
|
||||
if err := LinkAdd(vlan); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
vlan = &Vlan{
|
||||
LinkAttrs: LinkAttrs{Name: "bar"},
|
||||
BridgeBinding: &valueTrue,
|
||||
}
|
||||
|
||||
if err := LinkModify(vlan); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
link, err := LinkByName("bar")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if vlan, ok := link.(*Vlan); !ok {
|
||||
t.Fatalf("unexpected link type: %T", link)
|
||||
} else {
|
||||
if vlan.Gvrp == nil || *vlan.Gvrp != true {
|
||||
t.Fatalf("expected gvrp to be true, got %v", vlan.Gvrp)
|
||||
}
|
||||
if vlan.Mvrp == nil || *vlan.Mvrp != false {
|
||||
t.Fatalf("expected mvrp to be false, got %v", vlan.Mvrp)
|
||||
}
|
||||
if vlan.BridgeBinding == nil || *vlan.BridgeBinding != true {
|
||||
t.Fatalf("expected bridge binding to be true, got %v", vlan.BridgeBinding)
|
||||
}
|
||||
if vlan.LooseBinding == nil || *vlan.LooseBinding != false {
|
||||
t.Fatalf("expected loose binding to be false, got %v", vlan.LooseBinding)
|
||||
}
|
||||
if vlan.ReorderHdr == nil || *vlan.ReorderHdr != true {
|
||||
t.Fatalf("expected reorder hdr to be true, got %v", vlan.ReorderHdr)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestLinkAddDelMacvlan(t *testing.T) {
|
||||
tearDown := setUpNetlinkTest(t)
|
||||
defer tearDown()
|
||||
|
@@ -31,6 +31,20 @@ const (
|
||||
IFLA_VLAN_MAX = IFLA_VLAN_PROTOCOL
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_VLAN_QOS_UNSPEC = iota
|
||||
IFLA_VLAN_QOS_MAPPING
|
||||
IFLA_VLAN_QOS_MAX = IFLA_VLAN_QOS_MAPPING
|
||||
)
|
||||
|
||||
const (
|
||||
VLAN_FLAG_REORDER_HDR = 1 << iota
|
||||
VLAN_FLAG_GVRP
|
||||
VLAN_FLAG_LOOSE_BINDING
|
||||
VLAN_FLAG_MVRP
|
||||
VLAN_FLAG_BRIDGE_BINDING
|
||||
)
|
||||
|
||||
const (
|
||||
IFLA_NETKIT_UNSPEC = iota
|
||||
IFLA_NETKIT_PEER_INFO
|
||||
|
Reference in New Issue
Block a user