Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
24 changes: 23 additions & 1 deletion plugins/main/vlan/vlan.go
Original file line number Diff line number Diff line change
Expand Up @@ -52,9 +52,31 @@ func loadConf(args *skel.CmdArgs) (*NetConf, string, error) {
if err := json.Unmarshal(args.StdinData, n); err != nil {
return nil, "", fmt.Errorf("failed to load netconf: %v", err)
}

// Parse previous result
var result *current.Result
var err error
if n.NetConf.RawPrevResult != nil {
if err = version.ParsePrevResult(&n.NetConf); err != nil {
return nil, "", fmt.Errorf("could not parse prevResult: %v", err)
}

result, err = current.NewResultFromResult(n.PrevResult)
if err != nil {
return nil, "", fmt.Errorf("could not convert result to current version: %v", err)
}
}

if n.Master == "" {
return nil, "", fmt.Errorf("\"master\" field is required. It specifies the host interface name to create the VLAN for")
if result != nil && n.LinkContNs {
// Chaining scenario: CNI_IFNAME used as a master and new IfName is named <Master>.<VlanID>
n.Master = args.IfName
args.IfName = fmt.Sprintf("%s.%d", n.Master, n.VlanID)
} else {
return nil, "", fmt.Errorf("\"master\" field is required. It specifies the host interface name to create the VLAN for")
}
}

if n.VlanID < 0 || n.VlanID > 4094 {
return nil, "", fmt.Errorf("invalid VLAN ID %d (must be between 0 and 4095 inclusive)", n.VlanID)
}
Expand Down
83 changes: 83 additions & 0 deletions plugins/main/vlan/vlan_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ import (
"strings"
"syscall"

"github.com/onsi/ginkgo/v2"
. "github.com/onsi/ginkgo/v2"
. "github.com/onsi/gomega"
"github.com/vishvananda/netlink"
Expand Down Expand Up @@ -454,6 +455,88 @@ var _ = Describe("vlan Operations", func() {
Expect(err).NotTo(HaveOccurred())
})

Context("When master is not provided", func() {
masterInterface := ""

Context("When used as a chained plugin", func() {
Context("When linkInContainer is true", func() {
It(fmt.Sprintf("[%s] Use IFNAME as a master interface", ver), func() {
if !isInContainer {
ginkgo.Skip("Skipping because linkInContainer is false")
}

var err error
const IFNAME = MASTER_NAME_INCONTAINER
vlanID := 1234
NEWIFNAME := fmt.Sprintf("%s.%d", IFNAME, vlanID)

conf := fmt.Sprintf(`{
"cniVersion": "%s",
"name": "vlanTestv4",
"type": "vlan",
"master": "%s",
"vlanId": %d,
"linkInContainer": %t,
"ipam": {
"type": "host-local",
"subnet": "10.1.2.0/24",
"dataDir": "%s"
},
"prevResult": {
"cniVersion": "%s"
}
}`, ver, masterInterface, vlanID, isInContainer, dataDir, ver)

args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: targetNS.Path(),
IfName: IFNAME,
StdinData: []byte(conf),
}

t := newTesterByVersion(ver)

var result types.Result
var macAddress string
err = originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

var err error
result, _, err = testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())

macAddress = t.verifyResult(result, NEWIFNAME)
return nil
})
Expect(err).NotTo(HaveOccurred())

// Make sure vlan link exists in the target namespace
err = targetNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()

link, err := netlink.LinkByName(NEWIFNAME)
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().Name).To(Equal(NEWIFNAME))

if macAddress != "" {
hwaddr, err := net.ParseMAC(macAddress)
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().HardwareAddr).To(Equal(hwaddr))
}

addrs, err := netlink.AddrList(link, syscall.AF_INET)
Expect(err).NotTo(HaveOccurred())
Expect(addrs).To(HaveLen(1))
return nil
})
Expect(err).NotTo(HaveOccurred())
})
})
})
})

Describe("fails to create vlan link with invalid MTU", func() {
const confFmt = `{
"cniVersion": "%s",
Expand Down