mirror of
				https://github.com/vishvananda/netlink.git
				synced 2025-10-31 11:17:03 +08:00 
			
		
		
		
	vlan: add support for flags and qos maps
Signed-off-by: Gwendolyn <me@gwendolyn.dev>
This commit is contained in:
		 Gwendolyn
					Gwendolyn
				
			
				
					committed by
					
						 Alessandro Boch
						Alessandro Boch
					
				
			
			
				
	
			
			
			 Alessandro Boch
						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() | // Vlan links have ParentIndex set in their Attrs() | ||||||
| type Vlan struct { | 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