Skip to content

Commit

Permalink
Added vlan tag to the bridge cni plugin.
Browse files Browse the repository at this point in the history
  • Loading branch information
SchSeba committed Nov 19, 2018
1 parent 5af617e commit 9ff5e57
Show file tree
Hide file tree
Showing 3 changed files with 104 additions and 4 deletions.
4 changes: 4 additions & 0 deletions plugins/main/bridge/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ If the bridge is missing, the plugin will create one on first use and, if gatewa
"forceAddress": false,
"ipMasq": true,
"hairpinMode": true,
"vlan": 100
"ipam": {
"type": "host-local",
"subnet": "10.10.0.0/16"
Expand All @@ -41,3 +42,6 @@ If the bridge is missing, the plugin will create one on first use and, if gatewa
* `hairpinMode` (boolean, optional): set hairpin mode for interfaces on the bridge. Defaults to false.
* `ipam` (dictionary, required): IPAM configuration to be used for this network.
* `promiscMode` (boolean, optional): set promiscuous mode on the bridge. Defaults to false.
* `vlan` (int, optional): assign VLAN tag. Defaults to none.

*Note:* The VLAN parameter config the VLAN tag on the host end of the veth and also enable the vlan_filtering feature on the bridge interface.
22 changes: 18 additions & 4 deletions plugins/main/bridge/bridge.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,7 @@ type NetConf struct {
MTU int `json:"mtu"`
HairpinMode bool `json:"hairpinMode"`
PromiscMode bool `json:"promiscMode"`
Vlan int `json:"vlan"`
}

type gwInfo struct {
Expand Down Expand Up @@ -209,7 +210,8 @@ func bridgeByName(name string) (*netlink.Bridge, error) {
return br, nil
}

func ensureBridge(brName string, mtu int, promiscMode bool) (*netlink.Bridge, error) {
func ensureBridge(brName string, mtu int, promiscMode, VlanFiltering bool) (*netlink.Bridge, error) {

br := &netlink.Bridge{
LinkAttrs: netlink.LinkAttrs{
Name: brName,
Expand All @@ -220,6 +222,7 @@ func ensureBridge(brName string, mtu int, promiscMode bool) (*netlink.Bridge, er
// default packet limit
TxQLen: -1,
},
VlanFiltering: &VlanFiltering,
}

err := netlink.LinkAdd(br)
Expand Down Expand Up @@ -247,7 +250,7 @@ func ensureBridge(brName string, mtu int, promiscMode bool) (*netlink.Bridge, er
return br, nil
}

func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairpinMode bool) (*current.Interface, *current.Interface, error) {
func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairpinMode bool, vlanID int) (*current.Interface, *current.Interface, error) {
contIface := &current.Interface{}
hostIface := &current.Interface{}

Expand Down Expand Up @@ -284,6 +287,13 @@ func setupVeth(netns ns.NetNS, br *netlink.Bridge, ifName string, mtu int, hairp
return nil, nil, fmt.Errorf("failed to setup hairpin mode for %v: %v", hostVeth.Attrs().Name, err)
}

if vlanID != 0 {
err = netlink.BridgeVlanAdd(hostVeth, uint16(vlanID), true, true, false, true)
if err != nil {
return nil, nil, fmt.Errorf("failed to setup vlan tag on interface %q: %v", hostIface.Name, err)
}
}

return hostIface, contIface, nil
}

Expand All @@ -293,8 +303,12 @@ func calcGatewayIP(ipn *net.IPNet) net.IP {
}

func setupBridge(n *NetConf) (*netlink.Bridge, *current.Interface, error) {
VlanFiltering := false
if n.Vlan != 0 {
VlanFiltering = true
}
// create bridge if necessary
br, err := ensureBridge(n.BrName, n.MTU, n.PromiscMode)
br, err := ensureBridge(n.BrName, n.MTU, n.PromiscMode, VlanFiltering)
if err != nil {
return nil, nil, fmt.Errorf("failed to create bridge %q: %v", n.BrName, err)
}
Expand Down Expand Up @@ -353,7 +367,7 @@ func cmdAdd(args *skel.CmdArgs) error {
}
defer netns.Close()

hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode)
hostInterface, containerInterface, err := setupVeth(netns, br, args.IfName, n.MTU, n.HairpinMode, n.Vlan)
if err != nil {
return err
}
Expand Down
82 changes: 82 additions & 0 deletions plugins/main/bridge/bridge_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ package main

import (
"fmt"
"github.com/vishvananda/netlink/nl"
"io/ioutil"
"net"
"os"
Expand Down Expand Up @@ -48,6 +49,7 @@ type testCase struct {
ranges []rangeInfo // Ranges list (multiple subnets config)
isGW bool
expGWCIDRs []string // Expected gateway addresses in CIDR form
vlan int
}

// Range definition for each entry in the ranges list
Expand Down Expand Up @@ -81,6 +83,9 @@ const (
"isDefaultGateway": true,
"ipMasq": false`

vlan = `,
"vlan": %d`

ipamStartStr = `,
"ipam": {
"type": "host-local"`
Expand Down Expand Up @@ -117,6 +122,10 @@ const (
// for a test case.
func (tc testCase) netConfJSON(dataDir string) string {
conf := fmt.Sprintf(netConfStr, tc.cniVersion, BRNAME)
if tc.vlan != 0 {
conf += fmt.Sprintf(vlan, tc.vlan)
}

if tc.subnet != "" || tc.ranges != nil {
conf += ipamStartStr
if dataDir != "" {
Expand Down Expand Up @@ -239,6 +248,16 @@ func countIPAMIPs(path string) (int, error) {
return count, nil
}

func checkVlan(vlanId int, bridgeVlanInfo []*nl.BridgeVlanInfo) bool {
for _, vlan := range bridgeVlanInfo {
if vlan.Vid == uint16(vlanId) {
return true
}
}

return false
}

type cmdAddDelTester interface {
setNS(testNS ns.NetNS, targetNS ns.NetNS)
cmdAddTest(tc testCase, dataDir string)
Expand Down Expand Up @@ -303,6 +322,13 @@ func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) {
Expect(link.Attrs().HardwareAddr.String()).To(Equal(result.Interfaces[0].Mac))
bridgeMAC := link.Attrs().HardwareAddr.String()

// Check the bridge vlan filtering equals true
if tc.vlan != 0 {
Expect(*link.(*netlink.Bridge).VlanFiltering).To(Equal(true))
} else {
Expect(*link.(*netlink.Bridge).VlanFiltering).To(Equal(false))
}

// Ensure bridge has expected gateway address(es)
addrs, err := netlink.AddrList(link, netlink.FAMILY_ALL)
Expect(err).NotTo(HaveOccurred())
Expand Down Expand Up @@ -333,6 +359,15 @@ func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) {
Expect(link).To(BeAssignableToTypeOf(&netlink.Veth{}))
tester.vethName = result.Interfaces[1].Name

// check vlan exist on the interface
if tc.vlan != 0 {
interfaceMap, err := netlink.BridgeVlanList()
Expect(err).NotTo(HaveOccurred())
vlans, isExist := interfaceMap[int32(link.Attrs().Index)]
Expect(isExist).To(BeTrue())
Expect(checkVlan(tc.vlan, vlans)).To(BeTrue())
}

// Check that the bridge has a different mac from the veth
// If not, it means the bridge has an unstable mac and will change
// as ifs are added and removed
Expand Down Expand Up @@ -700,6 +735,53 @@ var _ = Describe("bridge Operations", func() {
}
})

It("configures and deconfigures a bridge and veth with default route and vlanID 100 with ADD/DEL for 0.3.0 config", func() {
testCases := []testCase{
{
// IPv4 only
subnet: "10.1.2.0/24",
expGWCIDRs: []string{"10.1.2.1/24"},
vlan: 100,
},
{
// IPv6 only
subnet: "2001:db8::0/64",
expGWCIDRs: []string{"2001:db8::1/64"},
vlan: 100,
},
{
// Dual-Stack
ranges: []rangeInfo{
{subnet: "192.168.0.0/24"},
{subnet: "fd00::0/64"},
},
expGWCIDRs: []string{
"192.168.0.1/24",
"fd00::1/64",
},
vlan: 100,
},
{
// 3 Subnets (1 IPv4 and 2 IPv6 subnets)
ranges: []rangeInfo{
{subnet: "192.168.0.0/24"},
{subnet: "fd00::0/64"},
{subnet: "2001:db8::0/64"},
},
expGWCIDRs: []string{
"192.168.0.1/24",
"fd00::1/64",
"2001:db8::1/64",
},
vlan: 100,
},
}
for _, tc := range testCases {
tc.cniVersion = "0.3.0"
cmdAddDelTest(originalNS, tc, dataDir)
}
})

It("configures and deconfigures a bridge and veth with default route with ADD/DEL for 0.3.1 config", func() {
testCases := []testCase{
{
Expand Down

0 comments on commit 9ff5e57

Please sign in to comment.