Skip to content

Commit 090af7d

Browse files
Date Huangtjjh89017
Date Huang
authored andcommitted
bridge: add vlan trunk support
add vlan trunk support for veth vlan trunk only support L2 only mode without any IPAM refer ovs-cni design https://github.com/k8snetworkplumbingwg/ovs-cni/blob/main/pkg/plugin/plugin.go design: origin "vlan" option will be PVID or untagged vlan for the network. "vlanTrunk" will setup tagged vlan for veth. entry type: `{ "id": 100 }` will specify only tagged vlan 100 `{ "minID": 100, "maxID": 120 }` will specify tagged vlan from 100 to 120 (include 100 and 120) vlanTrunk is a list of above entry type, so you can use this to add tagged vlan `[ { "id": 100 }, { "minID": 1000, "maxID": 2000 } ]` complete config will be like this { "cniVersion": "0.3.1", "name": "mynet", "type": "bridge", "bridge": "mynet0", "vlan": 100, "vlanTrunk": [ { "id": 101 }, { "minID": 1000, "maxID": 2000 }, { "minID": 3000, "maxID": 4000 } ], "ipam": {} } Signed-off-by: Date Huang <[email protected]>
1 parent 9f1f9a5 commit 090af7d

File tree

2 files changed

+278
-26
lines changed

2 files changed

+278
-26
lines changed

plugins/main/bridge/bridge.go

Lines changed: 109 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@ import (
2121
"net"
2222
"os"
2323
"runtime"
24+
"sort"
2425
"syscall"
2526
"time"
2627

@@ -46,18 +47,19 @@ const defaultBrName = "cni0"
4647

4748
type NetConf struct {
4849
types.NetConf
49-
BrName string `json:"bridge"`
50-
IsGW bool `json:"isGateway"`
51-
IsDefaultGW bool `json:"isDefaultGateway"`
52-
ForceAddress bool `json:"forceAddress"`
53-
IPMasq bool `json:"ipMasq"`
54-
MTU int `json:"mtu"`
55-
HairpinMode bool `json:"hairpinMode"`
56-
PromiscMode bool `json:"promiscMode"`
57-
Vlan int `json:"vlan"`
58-
PreserveDefaultVlan bool `json:"preserveDefaultVlan"`
59-
MacSpoofChk bool `json:"macspoofchk,omitempty"`
60-
EnableDad bool `json:"enabledad,omitempty"`
50+
BrName string `json:"bridge"`
51+
IsGW bool `json:"isGateway"`
52+
IsDefaultGW bool `json:"isDefaultGateway"`
53+
ForceAddress bool `json:"forceAddress"`
54+
IPMasq bool `json:"ipMasq"`
55+
MTU int `json:"mtu"`
56+
HairpinMode bool `json:"hairpinMode"`
57+
PromiscMode bool `json:"promiscMode"`
58+
Vlan int `json:"vlan"`
59+
VlanTrunk []*VlanTrunk `json:"vlanTrunk,omitempty"`
60+
PreserveDefaultVlan bool `json:"preserveDefaultVlan"`
61+
MacSpoofChk bool `json:"macspoofchk,omitempty"`
62+
EnableDad bool `json:"enabledad,omitempty"`
6163

6264
Args struct {
6365
Cni BridgeArgs `json:"cni,omitempty"`
@@ -66,7 +68,14 @@ type NetConf struct {
6668
Mac string `json:"mac,omitempty"`
6769
} `json:"runtimeConfig,omitempty"`
6870

69-
mac string
71+
mac string
72+
vlans []int
73+
}
74+
75+
type VlanTrunk struct {
76+
MinID *int `json:"minID,omitempty"`
77+
MaxID *int `json:"maxID,omitempty"`
78+
ID *int `json:"id,omitempty"`
7079
}
7180

7281
type BridgeArgs struct {
@@ -104,6 +113,17 @@ func loadNetConf(bytes []byte, envArgs string) (*NetConf, string, error) {
104113
if n.Vlan < 0 || n.Vlan > 4094 {
105114
return nil, "", fmt.Errorf("invalid VLAN ID %d (must be between 0 and 4094)", n.Vlan)
106115
}
116+
var err error
117+
n.vlans, err = collectVlanTrunk(n.VlanTrunk)
118+
if err != nil {
119+
// fail to parsing
120+
return nil, "", err
121+
}
122+
123+
// Currently bridge CNI only support access port(untagged only) or trunk port(tagged only)
124+
if n.Vlan > 0 && n.vlans != nil {
125+
return nil, "", errors.New("cannot set vlan and vlanTrunk at the same time")
126+
}
107127

108128
if envArgs != "" {
109129
e := MacEnvArgs{}
@@ -127,6 +147,61 @@ func loadNetConf(bytes []byte, envArgs string) (*NetConf, string, error) {
127147
return n, n.CNIVersion, nil
128148
}
129149

150+
// This method is copied from https://github.com/k8snetworkplumbingwg/ovs-cni/blob/v0.27.2/pkg/plugin/plugin.go
151+
func collectVlanTrunk(vlanTrunk []*VlanTrunk) ([]int, error) {
152+
if vlanTrunk == nil {
153+
return nil, nil
154+
}
155+
156+
vlanMap := make(map[int]struct{})
157+
for _, item := range vlanTrunk {
158+
var minID int
159+
var maxID int
160+
var ID int
161+
162+
switch {
163+
case item.MinID != nil && item.MaxID != nil:
164+
minID = *item.MinID
165+
if minID <= 0 || minID > 4094 {
166+
return nil, errors.New("incorrect trunk minID parameter")
167+
}
168+
maxID = *item.MaxID
169+
if maxID <= 0 || maxID > 4094 {
170+
return nil, errors.New("incorrect trunk maxID parameter")
171+
}
172+
if maxID < minID {
173+
return nil, errors.New("minID is greater than maxID in trunk parameter")
174+
}
175+
for v := minID; v <= maxID; v++ {
176+
vlanMap[v] = struct{}{}
177+
}
178+
case item.MinID == nil && item.MaxID != nil:
179+
return nil, errors.New("minID and maxID should be configured simultaneously, minID is missing")
180+
case item.MinID != nil && item.MaxID == nil:
181+
return nil, errors.New("minID and maxID should be configured simultaneously, maxID is missing")
182+
}
183+
184+
// single vid
185+
if item.ID != nil {
186+
ID = *item.ID
187+
if ID <= 0 || ID > 4094 {
188+
return nil, errors.New("incorrect trunk id parameter")
189+
}
190+
vlanMap[ID] = struct{}{}
191+
}
192+
}
193+
194+
if len(vlanMap) == 0 {
195+
return nil, nil
196+
}
197+
vlans := make([]int, 0, len(vlanMap))
198+
for k := range vlanMap {
199+
vlans = append(vlans, k)
200+
}
201+
sort.Slice(vlans, func(i int, j int) bool { return vlans[i] < vlans[j] })
202+
return vlans, nil
203+
}
204+
130205
// calcGateways processes the results from the IPAM plugin and does the
131206
// following for each IP family:
132207
// - Calculates and compiles a list of gateway addresses
@@ -316,7 +391,7 @@ func ensureVlanInterface(br *netlink.Bridge, vlanID int, preserveDefaultVlan boo
316391
return nil, fmt.Errorf("faild to find host namespace: %v", err)
317392
}
318393

319-
_, brGatewayIface, err := setupVeth(hostNS, br, name, br.MTU, false, vlanID, preserveDefaultVlan, "")
394+
_, brGatewayIface, err := setupVeth(hostNS, br, name, br.MTU, false, vlanID, nil, preserveDefaultVlan, "")
320395
if err != nil {
321396
return nil, fmt.Errorf("faild to create vlan gateway %q: %v", name, err)
322397
}
@@ -335,7 +410,7 @@ func ensureVlanInterface(br *netlink.Bridge, vlanID int, preserveDefaultVlan boo
335410
return brGatewayVeth, nil
336411
}
337412

338-
func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairpinMode bool, vlanID int, preserveDefaultVlan bool, mac string) (*current.Interface, *current.Interface, error) {
413+
func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairpinMode bool, vlanID int, vlans []int, preserveDefaultVlan bool, mac string) (*current.Interface, *current.Interface, error) {
339414
contIface := &current.Interface{}
340415
hostIface := &current.Interface{}
341416

@@ -372,20 +447,28 @@ func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairp
372447
return nil, nil, fmt.Errorf("failed to setup hairpin mode for %v: %v", hostVeth.Attrs().Name, err)
373448
}
374449

375-
if vlanID != 0 {
376-
if !preserveDefaultVlan {
377-
err = removeDefaultVlan(hostVeth)
378-
if err != nil {
379-
return nil, nil, fmt.Errorf("failed to remove default vlan on interface %q: %v", hostIface.Name, err)
380-
}
450+
if (vlanID != 0 || len(vlans) > 0) && !preserveDefaultVlan {
451+
err = removeDefaultVlan(hostVeth)
452+
if err != nil {
453+
return nil, nil, fmt.Errorf("failed to remove default vlan on interface %q: %v", hostIface.Name, err)
381454
}
455+
}
382456

457+
// Currently bridge CNI only support access port(untagged only) or trunk port(tagged only)
458+
if vlanID != 0 {
383459
err = netlink.BridgeVlanAdd(hostVeth, uint16(vlanID), true, true, false, true)
384460
if err != nil {
385461
return nil, nil, fmt.Errorf("failed to setup vlan tag on interface %q: %v", hostIface.Name, err)
386462
}
387463
}
388464

465+
for _, v := range vlans {
466+
err = netlink.BridgeVlanAdd(hostVeth, uint16(v), false, false, false, true)
467+
if err != nil {
468+
return nil, nil, fmt.Errorf("failed to setup vlan tag on interface %q: %w", hostIface.Name, err)
469+
}
470+
}
471+
389472
return hostIface, contIface, nil
390473
}
391474

@@ -414,7 +497,10 @@ func calcGatewayIP(ipn *net.IPNet) net.IP {
414497
}
415498

416499
func setupBridge(n *NetConf) (*netlink.Bridge, *current.Interface, error) {
417-
vlanFiltering := n.Vlan != 0
500+
vlanFiltering := false
501+
if n.Vlan != 0 || n.VlanTrunk != nil {
502+
vlanFiltering = true
503+
}
418504
// create bridge if necessary
419505
br, err := ensureBridge(n.BrName, n.MTU, n.PromiscMode, vlanFiltering)
420506
if err != nil {
@@ -463,7 +549,7 @@ func cmdAdd(args *skel.CmdArgs) error {
463549
}
464550
defer netns.Close()
465551

466-
hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode, n.Vlan, n.PreserveDefaultVlan, n.mac)
552+
hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode, n.Vlan, n.vlans, n.PreserveDefaultVlan, n.mac)
467553
if err != nil {
468554
return err
469555
}

0 commit comments

Comments
 (0)