mirror of
https://github.com/vishvananda/netlink.git
synced 2025-10-24 00:03:24 +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
7
link.go
7
link.go
@@ -292,6 +292,13 @@ type Vlan struct {
|
|||||||
LinkAttrs
|
LinkAttrs
|
||||||
VlanId int
|
VlanId int
|
||||||
VlanProtocol VlanProtocol
|
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 {
|
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))
|
native.PutUint16(b, uint16(link.VlanId))
|
||||||
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
|
data := linkInfo.AddRtAttr(nl.IFLA_INFO_DATA, nil)
|
||||||
data.AddRtAttr(nl.IFLA_VLAN_ID, b)
|
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 {
|
if link.VlanProtocol != VLAN_PROTOCOL_UNKNOWN {
|
||||||
data.AddRtAttr(nl.IFLA_VLAN_PROTOCOL, htons(uint16(link.VlanProtocol)))
|
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) {
|
func parseVlanData(link Link, data []syscall.NetlinkRouteAttr) {
|
||||||
vlan := link.(*Vlan)
|
vlan := link.(*Vlan)
|
||||||
for _, datum := range data {
|
for _, datum := range data {
|
||||||
switch datum.Attr.Type {
|
switch datum.Attr.Type {
|
||||||
case nl.IFLA_VLAN_ID:
|
case nl.IFLA_VLAN_ID:
|
||||||
vlan.VlanId = int(native.Uint16(datum.Value[0:2]))
|
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:
|
case nl.IFLA_VLAN_PROTOCOL:
|
||||||
vlan.VlanProtocol = VlanProtocol(int(ntohs(datum.Value[0:2])))
|
vlan.VlanProtocol = VlanProtocol(int(ntohs(datum.Value[0:2])))
|
||||||
}
|
}
|
||||||
|
168
link_test.go
168
link_test.go
@@ -10,6 +10,7 @@ import (
|
|||||||
"net"
|
"net"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"strings"
|
"strings"
|
||||||
"syscall"
|
"syscall"
|
||||||
@@ -919,13 +920,178 @@ func TestLinkAddDelVlan(t *testing.T) {
|
|||||||
t.Fatal(err)
|
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 {
|
if err := LinkDel(parent); err != nil {
|
||||||
t.Fatal(err)
|
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) {
|
func TestLinkAddDelMacvlan(t *testing.T) {
|
||||||
tearDown := setUpNetlinkTest(t)
|
tearDown := setUpNetlinkTest(t)
|
||||||
defer tearDown()
|
defer tearDown()
|
||||||
|
@@ -31,6 +31,20 @@ const (
|
|||||||
IFLA_VLAN_MAX = IFLA_VLAN_PROTOCOL
|
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 (
|
const (
|
||||||
IFLA_NETKIT_UNSPEC = iota
|
IFLA_NETKIT_UNSPEC = iota
|
||||||
IFLA_NETKIT_PEER_INFO
|
IFLA_NETKIT_PEER_INFO
|
||||||
|
Reference in New Issue
Block a user