Merge remote-tracking branch 'upstream/master' into dev/static-args

This commit is contained in:
Tomofumi Hayashi
2018-09-05 14:39:16 +09:00
45 changed files with 1226 additions and 202 deletions

View File

@@ -128,7 +128,7 @@ func (d *DHCP) clearLease(contID, netName string) {
}
func getListener() (net.Listener, error) {
l, err := activation.Listeners(true)
l, err := activation.Listeners()
if err != nil {
return nil, err
}

View File

@@ -44,7 +44,8 @@ func main() {
os.Exit(1)
}
} else {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
}
@@ -72,6 +73,11 @@ func cmdDel(args *skel.CmdArgs) error {
return nil
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}
func rpcCall(method string, args *skel.CmdArgs, result interface{}) error {
client, err := rpc.DialHTTP("unix", socketPath)
if err != nil {

View File

@@ -372,7 +372,7 @@ var _ = Describe("IPAM config", func() {
"type": "host-local",
"ranges": [
[{"subnet": "10.1.2.0/24"}],
[{"subnet": "2001:db8:1::/24"}]
[{"subnet": "2001:db8:1::/48"}]
]
}
}`

View File

@@ -40,6 +40,12 @@ func (r *Range) Canonicalize() error {
return fmt.Errorf("IPNet IP and Mask version mismatch")
}
// Ensure Subnet IP is the network address, not some other address
networkIP := r.Subnet.IP.Mask(r.Subnet.Mask)
if !r.Subnet.IP.Equal(networkIP) {
return fmt.Errorf("Network has host bits set. For a subnet mask of length %d the network address is %s", ones, networkIP.String())
}
// If the gateway is nil, claim .1
if r.Gateway == nil {
r.Gateway = ip.NextIP(r.Subnet.IP)

View File

@@ -25,7 +25,7 @@ import (
)
var _ = Describe("IP ranges", func() {
It("should generate sane defaults for ipv4", func() {
It("should generate sane defaults for ipv4 with a clean prefix", func() {
snstr := "192.0.2.0/24"
r := Range{Subnet: mustSubnet(snstr)}
@@ -33,7 +33,7 @@ var _ = Describe("IP ranges", func() {
Expect(err).NotTo(HaveOccurred())
Expect(r).To(Equal(Range{
Subnet: mustSubnet(snstr),
Subnet: networkSubnet(snstr),
RangeStart: net.IP{192, 0, 2, 1},
RangeEnd: net.IP{192, 0, 2, 254},
Gateway: net.IP{192, 0, 2, 1},
@@ -47,13 +47,41 @@ var _ = Describe("IP ranges", func() {
Expect(err).NotTo(HaveOccurred())
Expect(r).To(Equal(Range{
Subnet: mustSubnet(snstr),
Subnet: networkSubnet(snstr),
RangeStart: net.IP{192, 0, 2, 1},
RangeEnd: net.IP{192, 0, 2, 126},
Gateway: net.IP{192, 0, 2, 1},
}))
})
It("should generate sane defaults for ipv6", func() {
It("should reject ipv4 subnet using a masked address", func() {
snstr := "192.0.2.12/24"
r := Range{Subnet: mustSubnet(snstr)}
err := r.Canonicalize()
Expect(err).Should(MatchError("Network has host bits set. For a subnet mask of length 24 the network address is 192.0.2.0"))
})
It("should reject ipv6 subnet using a masked address", func() {
snstr := "2001:DB8:1::24:19ff:fee1:c44a/64"
r := Range{Subnet: mustSubnet(snstr)}
err := r.Canonicalize()
Expect(err).Should(MatchError("Network has host bits set. For a subnet mask of length 64 the network address is 2001:db8:1::"))
})
It("should reject ipv6 prefix with host bit set", func() {
snstr := "2001:DB8:24:19ff::/63"
r := Range{Subnet: mustSubnet(snstr)}
err := r.Canonicalize()
Expect(err).Should(MatchError("Network has host bits set. For a subnet mask of length 63 the network address is 2001:db8:24:19fe::"))
})
It("should reject ipv4 network with host bit set", func() {
snstr := "192.168.127.0/23"
r := Range{Subnet: mustSubnet(snstr)}
err := r.Canonicalize()
Expect(err).Should(MatchError("Network has host bits set. For a subnet mask of length 23 the network address is 192.168.126.0"))
})
It("should generate sane defaults for ipv6 with a clean prefix", func() {
snstr := "2001:DB8:1::/64"
r := Range{Subnet: mustSubnet(snstr)}
@@ -61,7 +89,7 @@ var _ = Describe("IP ranges", func() {
Expect(err).NotTo(HaveOccurred())
Expect(r).To(Equal(Range{
Subnet: mustSubnet(snstr),
Subnet: networkSubnet(snstr),
RangeStart: net.ParseIP("2001:DB8:1::1"),
RangeEnd: net.ParseIP("2001:DB8:1::ffff:ffff:ffff:ffff"),
Gateway: net.ParseIP("2001:DB8:1::1"),
@@ -75,16 +103,17 @@ var _ = Describe("IP ranges", func() {
})
It("should reject invalid RangeStart and RangeEnd specifications", func() {
r := Range{Subnet: mustSubnet("192.0.2.0/24"), RangeStart: net.ParseIP("192.0.3.0")}
snstr := "192.0.2.0/24"
r := Range{Subnet: mustSubnet(snstr), RangeStart: net.ParseIP("192.0.3.0")}
err := r.Canonicalize()
Expect(err).Should(MatchError("RangeStart 192.0.3.0 not in network 192.0.2.0/24"))
r = Range{Subnet: mustSubnet("192.0.2.0/24"), RangeEnd: net.ParseIP("192.0.4.0")}
r = Range{Subnet: mustSubnet(snstr), RangeEnd: net.ParseIP("192.0.4.0")}
err = r.Canonicalize()
Expect(err).Should(MatchError("RangeEnd 192.0.4.0 not in network 192.0.2.0/24"))
r = Range{
Subnet: mustSubnet("192.0.2.0/24"),
Subnet: networkSubnet(snstr),
RangeStart: net.ParseIP("192.0.2.50"),
RangeEnd: net.ParseIP("192.0.2.40"),
}
@@ -99,8 +128,9 @@ var _ = Describe("IP ranges", func() {
})
It("should parse all fields correctly", func() {
snstr := "192.0.2.0/24"
r := Range{
Subnet: mustSubnet("192.0.2.0/24"),
Subnet: mustSubnet(snstr),
RangeStart: net.ParseIP("192.0.2.40"),
RangeEnd: net.ParseIP("192.0.2.50"),
Gateway: net.ParseIP("192.0.2.254"),
@@ -109,7 +139,7 @@ var _ = Describe("IP ranges", func() {
Expect(err).NotTo(HaveOccurred())
Expect(r).To(Equal(Range{
Subnet: mustSubnet("192.0.2.0/24"),
Subnet: networkSubnet(snstr),
RangeStart: net.IP{192, 0, 2, 40},
RangeEnd: net.IP{192, 0, 2, 50},
Gateway: net.IP{192, 0, 2, 254},
@@ -207,3 +237,9 @@ func mustSubnet(s string) types.IPNet {
canonicalizeIP(&n.IP)
return types.IPNet(*n)
}
func networkSubnet(s string) types.IPNet {
net := mustSubnet(s)
net.IP = net.IP.Mask(net.Mask)
return net
}

View File

@@ -444,7 +444,7 @@ var _ = Describe("host-local Operations", func() {
"dataDir": "%s",
"ranges": [
[{"subnet":"172.16.1.0/24"}, { "subnet": "10.1.2.0/24" }],
[{ "subnet": "2001:db8:1::/24" }]
[{ "subnet": "2001:db8:1::/48" }]
]
},
"args": {

View File

@@ -29,7 +29,13 @@ import (
)
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}
func cmdAdd(args *skel.CmdArgs) error {

View File

@@ -57,7 +57,13 @@ type Address struct {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}
// canonicalizeIP makes sure a provided ip is in standard form
@@ -72,7 +78,9 @@ func canonicalizeIP(ip *net.IP) error {
return fmt.Errorf("IP %s not v4 nor v6", *ip)
}
// NewIPAMConfig creates a NetworkConfig from the given network name.
// LoadIPAMConfig creates IPAMConfig using json encoded configuration provided
// as `bytes`. At the moment values provided in envArgs are ignored so there
// is no possibility to overload the json configuration using envArgs
func LoadIPAMConfig(bytes []byte, envArgs string) (*IPAMConfig, string, error) {
n := Net{}
if err := json.Unmarshal(bytes, &n); err != nil {
@@ -167,7 +175,6 @@ func cmdAdd(args *skel.CmdArgs) error {
Gateway: v.Gateway})
}
result.Routes = ipamConf.Routes
return types.PrintResult(result, confVersion)
}

View File

@@ -19,6 +19,7 @@ import (
"errors"
"fmt"
"net"
"os"
"runtime"
"syscall"
@@ -36,6 +37,9 @@ import (
"github.com/vishvananda/netlink"
)
// For testcases to force an error after IPAM has been performed
var debugPostIPAMError error
const defaultBrName = "cni0"
type NetConf struct {
@@ -323,6 +327,8 @@ func enableIPForward(family int) error {
}
func cmdAdd(args *skel.CmdArgs) error {
var success bool = false
n, cniVersion, err := loadNetConf(args.StdinData)
if err != nil {
return err
@@ -358,6 +364,15 @@ func cmdAdd(args *skel.CmdArgs) error {
return err
}
// release IP in case of failure
defer func() {
if !success {
os.Setenv("CNI_COMMAND", "DEL")
ipam.ExecDel(n.IPAM.Type, args.StdinData)
os.Setenv("CNI_COMMAND", "ADD")
}
}()
// Convert whatever the IPAM result was into the current Result type
result, err := current.NewResultFromResult(r)
if err != nil {
@@ -454,6 +469,13 @@ func cmdAdd(args *skel.CmdArgs) error {
result.DNS = n.DNS
// Return an error requested by testcases, if any
if debugPostIPAMError != nil {
return debugPostIPAMError
}
success = true
return types.PrintResult(result, cniVersion)
}
@@ -502,5 +524,11 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}

View File

@@ -16,7 +16,9 @@ package main
import (
"fmt"
"io/ioutil"
"net"
"os"
"strings"
"github.com/containernetworking/cni/pkg/skel"
@@ -83,6 +85,9 @@ const (
"ipam": {
"type": "host-local"`
ipamDataDirStr = `,
"dataDir": "%s"`
// Single subnet configuration (legacy)
subnetConfStr = `,
"subnet": "%s"`
@@ -110,10 +115,13 @@ const (
// netConfJSON() generates a JSON network configuration string
// for a test case.
func (tc testCase) netConfJSON() string {
func (tc testCase) netConfJSON(dataDir string) string {
conf := fmt.Sprintf(netConfStr, tc.cniVersion, BRNAME)
if tc.subnet != "" || tc.ranges != nil {
conf += ipamStartStr
if dataDir != "" {
conf += fmt.Sprintf(ipamDataDirStr, dataDir)
}
if tc.subnet != "" {
conf += tc.subnetConfig()
}
@@ -152,8 +160,8 @@ var counter uint
// createCmdArgs generates network configuration and creates command
// arguments for a test case.
func (tc testCase) createCmdArgs(targetNS ns.NetNS) *skel.CmdArgs {
conf := tc.netConfJSON()
func (tc testCase) createCmdArgs(targetNS ns.NetNS, dataDir string) *skel.CmdArgs {
conf := tc.netConfJSON(dataDir)
defer func() { counter += 1 }()
return &skel.CmdArgs{
ContainerID: fmt.Sprintf("dummy-%d", counter),
@@ -213,9 +221,27 @@ func ipVersion(ip net.IP) string {
return "6"
}
func countIPAMIPs(path string) (int, error) {
count := 0
files, err := ioutil.ReadDir(path)
if err != nil {
return -1, err
}
for _, file := range files {
if file.IsDir() {
continue
}
if net.ParseIP(file.Name()) != nil {
count++
}
}
return count, nil
}
type cmdAddDelTester interface {
setNS(testNS ns.NetNS, targetNS ns.NetNS)
cmdAddTest(tc testCase)
cmdAddTest(tc testCase, dataDir string)
cmdDelTest(tc testCase)
}
@@ -240,9 +266,9 @@ func (tester *testerV03x) setNS(testNS ns.NetNS, targetNS ns.NetNS) {
tester.targetNS = targetNS
}
func (tester *testerV03x) cmdAddTest(tc testCase) {
func (tester *testerV03x) cmdAddTest(tc testCase, dataDir string) {
// Generate network config and command arguments
tester.args = tc.createCmdArgs(tester.targetNS)
tester.args = tc.createCmdArgs(tester.targetNS, dataDir)
// Execute cmdADD on the plugin
var result *current.Result
@@ -419,9 +445,9 @@ func (tester *testerV01xOr02x) setNS(testNS ns.NetNS, targetNS ns.NetNS) {
tester.targetNS = targetNS
}
func (tester *testerV01xOr02x) cmdAddTest(tc testCase) {
func (tester *testerV01xOr02x) cmdAddTest(tc testCase, dataDir string) {
// Generate network config and calculate gateway addresses
tester.args = tc.createCmdArgs(tester.targetNS)
tester.args = tc.createCmdArgs(tester.targetNS, dataDir)
// Execute cmdADD on the plugin
err := tester.testNS.Do(func(ns.NetNS) error {
@@ -537,7 +563,7 @@ func (tester *testerV01xOr02x) cmdDelTest(tc testCase) {
Expect(err).NotTo(HaveOccurred())
}
func cmdAddDelTest(testNS ns.NetNS, tc testCase) {
func cmdAddDelTest(testNS ns.NetNS, tc testCase, dataDir string) {
// Get a Add/Del tester based on test case version
tester := testerByVersion(tc.cniVersion)
@@ -547,7 +573,7 @@ func cmdAddDelTest(testNS ns.NetNS, tc testCase) {
tester.setNS(testNS, targetNS)
// Test IP allocation
tester.cmdAddTest(tc)
tester.cmdAddTest(tc, dataDir)
// Test IP Release
tester.cmdDelTest(tc)
@@ -558,15 +584,23 @@ func cmdAddDelTest(testNS ns.NetNS, tc testCase) {
var _ = Describe("bridge Operations", func() {
var originalNS ns.NetNS
var dataDir string
BeforeEach(func() {
// Create a new NetNS so we don't modify the host
var err error
originalNS, err = testutils.NewNS()
Expect(err).NotTo(HaveOccurred())
dataDir, err = ioutil.TempDir("", "bridge_test")
Expect(err).NotTo(HaveOccurred())
// Do not emulate an error, each test will set this if needed
debugPostIPAMError = nil
})
AfterEach(func() {
Expect(os.RemoveAll(dataDir)).To(Succeed())
Expect(originalNS.Close()).To(Succeed())
})
@@ -661,7 +695,7 @@ var _ = Describe("bridge Operations", func() {
}
for _, tc := range testCases {
tc.cniVersion = "0.3.0"
cmdAddDelTest(originalNS, tc)
cmdAddDelTest(originalNS, tc, dataDir)
}
})
@@ -691,7 +725,7 @@ var _ = Describe("bridge Operations", func() {
}
for _, tc := range testCases {
tc.cniVersion = "0.3.1"
cmdAddDelTest(originalNS, tc)
cmdAddDelTest(originalNS, tc, dataDir)
}
})
@@ -707,7 +741,7 @@ var _ = Describe("bridge Operations", func() {
Expect(err).NotTo(HaveOccurred())
defer targetNS.Close()
tester.setNS(originalNS, targetNS)
tester.args = tc.createCmdArgs(targetNS)
tester.args = tc.createCmdArgs(targetNS, dataDir)
// Execute cmdDEL on the plugin, expect no errors
tester.cmdDelTest(tc)
@@ -739,7 +773,7 @@ var _ = Describe("bridge Operations", func() {
}
for _, tc := range testCases {
tc.cniVersion = "0.1.0"
cmdAddDelTest(originalNS, tc)
cmdAddDelTest(originalNS, tc, dataDir)
}
})
@@ -909,11 +943,44 @@ var _ = Describe("bridge Operations", func() {
Expect(err).NotTo(HaveOccurred())
origMac := link.Attrs().HardwareAddr
cmdAddDelTest(originalNS, tc)
cmdAddDelTest(originalNS, tc, dataDir)
link, err = netlink.LinkByName(BRNAME)
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().HardwareAddr).To(Equal(origMac))
}
})
It("checks ip release in case of error", func() {
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
tc := testCase{
cniVersion: "0.3.1",
subnet: "10.1.2.0/24",
}
_, _, err := setupBridge(tc.netConf())
Expect(err).NotTo(HaveOccurred())
args := tc.createCmdArgs(originalNS, dataDir)
// get number of allocated IPs before asking for a new one
before, err := countIPAMIPs(dataDir)
Expect(err).NotTo(HaveOccurred())
debugPostIPAMError = fmt.Errorf("debugPostIPAMError")
_, _, err = testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).To(MatchError("debugPostIPAMError"))
// get number of allocated IPs after failure
after, err := countIPAMIPs(dataDir)
Expect(err).NotTo(HaveOccurred())
Expect(before).To(Equal(after))
return nil
})
Expect(err).NotTo(HaveOccurred())
})
})

View File

@@ -217,5 +217,11 @@ func getLink(devname, hwaddr, kernelpath string) (netlink.Link, error) {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}

View File

@@ -245,5 +245,11 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}

View File

@@ -15,6 +15,8 @@
package main
import (
"fmt"
"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/cni/pkg/version"
@@ -68,5 +70,11 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}

View File

@@ -58,6 +58,8 @@ var _ = Describe("Loopback", func() {
Context("when given a network namespace", func() {
It("sets the lo device to UP", func() {
Skip("TODO: add network name")
command.Env = append(environ, fmt.Sprintf("CNI_COMMAND=%s", "ADD"))
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)
@@ -78,6 +80,8 @@ var _ = Describe("Loopback", func() {
})
It("sets the lo device to DOWN", func() {
Skip("TODO: add network name")
command.Env = append(environ, fmt.Sprintf("CNI_COMMAND=%s", "DEL"))
session, err := gexec.Start(command, GinkgoWriter, GinkgoWriter)

View File

@@ -255,5 +255,11 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}

View File

@@ -285,5 +285,11 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}

View File

@@ -192,5 +192,11 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}

View File

@@ -48,10 +48,10 @@ The following is an example [json configuration list](https://github.com/contain
The result is an `ifb` device in the host namespace redirecting to the `host-interface`, with `tc tbf` applied on the `ifb` device and the `container-interface`
## Network configuration reference
* ingressRate: is the rate in Kbps at which traffic can enter an interface. (See http://man7.org/linux/man-pages/man8/tbf.8.html)
* ingressBurst: is the maximum amount in Kb that tokens can be made available for instantaneously. (See http://man7.org/linux/man-pages/man8/tbf.8.html)
* egressRate: is the rate in Kbps at which traffic can leave an interface. (See http://man7.org/linux/man-pages/man8/tbf.8.html)
* egressBurst: is the maximum amount in Kb that tokens can be made available for instantaneously. (See http://man7.org/linux/man-pages/man8/tbf.8.html)
* ingressRate: is the rate in bps at which traffic can enter an interface. (See http://man7.org/linux/man-pages/man8/tbf.8.html)
* ingressBurst: is the maximum amount in bits that tokens can be made available for instantaneously. (See http://man7.org/linux/man-pages/man8/tbf.8.html)
* egressRate: is the rate in bps at which traffic can leave an interface. (See http://man7.org/linux/man-pages/man8/tbf.8.html)
* egressBurst: is the maximum amount in bits that tokens can be made available for instantaneously. (See http://man7.org/linux/man-pages/man8/tbf.8.html)
Both ingressRate and ingressBurst must be set in order to limit ingress bandwidth. If neither one is set, then ingress bandwidth is not limited.
Both egressRate and egressBurst must be set in order to limit egress bandwidth. If neither one is set, then egress bandwidth is not limited.

View File

@@ -80,7 +80,7 @@ var _ = Describe("bandwidth test", func() {
"ingressRate": 8,
"ingressBurst": 8,
"egressRate": 16,
"egressBurst": 9,
"egressBurst": 8,
"prevResult": {
"interfaces": [
{
@@ -135,7 +135,7 @@ var _ = Describe("bandwidth test", func() {
Expect(qdiscs[0]).To(BeAssignableToTypeOf(&netlink.Tbf{}))
Expect(qdiscs[0].(*netlink.Tbf).Rate).To(Equal(uint64(2)))
Expect(qdiscs[0].(*netlink.Tbf).Limit).To(Equal(uint32(9)))
Expect(qdiscs[0].(*netlink.Tbf).Limit).To(Equal(uint32(1)))
hostVethLink, err := netlink.LinkByName(hostIfname)
Expect(err).NotTo(HaveOccurred())
@@ -163,7 +163,7 @@ var _ = Describe("bandwidth test", func() {
Expect(qdiscs[0]).To(BeAssignableToTypeOf(&netlink.Tbf{}))
Expect(qdiscs[0].(*netlink.Tbf).Rate).To(Equal(uint64(1)))
Expect(qdiscs[0].(*netlink.Tbf).Limit).To(Equal(uint32(8)))
Expect(qdiscs[0].(*netlink.Tbf).Limit).To(Equal(uint32(1)))
return nil
})).To(Succeed())
@@ -176,8 +176,8 @@ var _ = Describe("bandwidth test", func() {
"type": "bandwidth",
"ingressRate": 0,
"ingressBurst": 0,
"egressRate": 8,
"egressBurst": 1,
"egressRate": 8000,
"egressBurst": 80,
"prevResult": {
"interfaces": [
{
@@ -245,8 +245,8 @@ var _ = Describe("bandwidth test", func() {
"type": "bandwidth",
"egressRate": 0,
"egressBurst": 0,
"ingressRate": 8,
"ingressBurst": 1,
"ingressRate": 8000,
"ingressBurst": 80,
"prevResult": {
"interfaces": [
{
@@ -302,8 +302,8 @@ var _ = Describe("bandwidth test", func() {
Expect(qdiscs[0].Attrs().LinkIndex).To(Equal(containerIfLink.Attrs().Index))
Expect(qdiscs[0]).To(BeAssignableToTypeOf(&netlink.Tbf{}))
Expect(qdiscs[0].(*netlink.Tbf).Rate).To(Equal(uint64(1)))
Expect(qdiscs[0].(*netlink.Tbf).Limit).To(Equal(uint32(1)))
Expect(qdiscs[0].(*netlink.Tbf).Rate).To(Equal(uint64(1000)))
Expect(qdiscs[0].(*netlink.Tbf).Limit).To(Equal(uint32(35)))
return nil
})).To(Succeed())
@@ -426,7 +426,7 @@ var _ = Describe("bandwidth test", func() {
Expect(qdiscs[0]).To(BeAssignableToTypeOf(&netlink.Tbf{}))
Expect(qdiscs[0].(*netlink.Tbf).Rate).To(Equal(uint64(2)))
Expect(qdiscs[0].(*netlink.Tbf).Limit).To(Equal(uint32(9)))
Expect(qdiscs[0].(*netlink.Tbf).Limit).To(Equal(uint32(1)))
hostVethLink, err := netlink.LinkByName(hostIfname)
Expect(err).NotTo(HaveOccurred())
@@ -454,7 +454,7 @@ var _ = Describe("bandwidth test", func() {
Expect(qdiscs[0]).To(BeAssignableToTypeOf(&netlink.Tbf{}))
Expect(qdiscs[0].(*netlink.Tbf).Rate).To(Equal(uint64(1)))
Expect(qdiscs[0].(*netlink.Tbf).Limit).To(Equal(uint32(8)))
Expect(qdiscs[0].(*netlink.Tbf).Limit).To(Equal(uint32(1)))
return nil
})).To(Succeed())
@@ -625,7 +625,7 @@ var _ = Describe("bandwidth test", func() {
defer GinkgoRecover()
containerWithTbfRes, _, err = testutils.CmdAdd(containerWithTbfNS.Path(), "dummy", containerWithTbfIFName, []byte(ptpConf), func() error {
r, err := invoke.DelegateAdd("ptp", []byte(ptpConf))
r, err := invoke.DelegateAdd("ptp", []byte(ptpConf), nil)
Expect(r.Print()).To(Succeed())
return err
@@ -633,7 +633,7 @@ var _ = Describe("bandwidth test", func() {
Expect(err).NotTo(HaveOccurred())
containerWithoutTbfRes, _, err = testutils.CmdAdd(containerWithoutTbfNS.Path(), "dummy2", containerWithoutTbfIFName, []byte(ptpConf), func() error {
r, err := invoke.DelegateAdd("ptp", []byte(ptpConf))
r, err := invoke.DelegateAdd("ptp", []byte(ptpConf), nil)
Expect(r.Print()).To(Succeed())
return err

View File

@@ -125,9 +125,10 @@ func createTBF(rateInBits, burstInBits, linkIndex int) error {
return fmt.Errorf("invalid burst: %d", burstInBits)
}
rateInBytes := rateInBits / 8
bufferInBytes := buffer(uint64(rateInBytes), uint32(burstInBits))
burstInBytes := burstInBits / 8
bufferInBytes := buffer(uint64(rateInBytes), uint32(burstInBytes))
latency := latencyInUsec(latencyInMillis)
limitInBytes := limit(uint64(rateInBytes), latency, uint32(bufferInBytes))
limitInBytes := limit(uint64(rateInBytes), latency, uint32(burstInBytes))
qdisc := &netlink.Tbf{
QdiscAttrs: netlink.QdiscAttrs{
@@ -159,7 +160,7 @@ func buffer(rate uint64, burst uint32) uint32 {
}
func limit(rate uint64, latency float64, buffer uint32) uint32 {
return uint32(float64(rate) / float64(netlink.TIME_UNITS_PER_SEC) * (latency + float64(tick2Time(buffer))))
return uint32(float64(rate)*latency/float64(netlink.TIME_UNITS_PER_SEC)) + buffer
}
func latencyInUsec(latencyInMillis float64) float64 {

View File

@@ -32,11 +32,11 @@ import (
// BandwidthEntry corresponds to a single entry in the bandwidth argument,
// see CONVENTIONS.md
type BandwidthEntry struct {
IngressRate int `json:"ingressRate"` //Bandwidth rate in Kbps for traffic through container. 0 for no limit. If ingressRate is set, ingressBurst must also be set
IngressBurst int `json:"ingressBurst"` //Bandwidth burst in Kb for traffic through container. 0 for no limit. If ingressBurst is set, ingressRate must also be set
IngressRate int `json:"ingressRate"` //Bandwidth rate in bps for traffic through container. 0 for no limit. If ingressRate is set, ingressBurst must also be set
IngressBurst int `json:"ingressBurst"` //Bandwidth burst in bits for traffic through container. 0 for no limit. If ingressBurst is set, ingressRate must also be set
EgressRate int `json:"egressRate"` //Bandwidth rate in Kbps for traffic through container. 0 for no limit. If egressRate is set, egressBurst must also be set
EgressBurst int `json:"egressBurst"` //Bandwidth burst in Kb for traffic through container. 0 for no limit. If egressBurst is set, egressRate must also be set
EgressRate int `json:"egressRate"` //Bandwidth rate in bps for traffic through container. 0 for no limit. If egressRate is set, egressBurst must also be set
EgressBurst int `json:"egressBurst"` //Bandwidth burst in bits for traffic through container. 0 for no limit. If egressBurst is set, egressRate must also be set
}
func (bw *BandwidthEntry) isZero() bool {
@@ -232,5 +232,11 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.PluginSupports("0.3.0", "0.3.1", version.Current()))
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.PluginSupports("0.3.0", "0.3.1", version.Current()), "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}

View File

@@ -159,7 +159,7 @@ func delegateAdd(cid, dataDir string, netconf map[string]interface{}) error {
return err
}
result, err := invoke.DelegateAdd(netconf["type"].(string), netconfBytes)
result, err := invoke.DelegateAdd(netconf["type"].(string), netconfBytes, nil)
if err != nil {
return err
}
@@ -261,9 +261,15 @@ func cmdDel(args *skel.CmdArgs) error {
return fmt.Errorf("failed to parse netconf: %v", err)
}
return invoke.DelegateDel(n.Type, netconfBytes)
return invoke.DelegateDel(n.Type, netconfBytes, nil)
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}

View File

@@ -118,7 +118,13 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.PluginSupports("", "0.1.0", "0.2.0", "0.3.0", version.Current()))
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}
// parseConfig parses the supplied configuration (and prevResult) from stdin.

View File

@@ -21,6 +21,7 @@ import (
"encoding/json"
"fmt"
"io/ioutil"
"net"
"path/filepath"
"strings"
@@ -29,6 +30,7 @@ import (
"github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/cni/pkg/version"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/vishvananda/netlink"
)
// TuningConf represents the network tuning configuration.
@@ -37,14 +39,35 @@ type TuningConf struct {
SysCtl map[string]string `json:"sysctl"`
RawPrevResult map[string]interface{} `json:"prevResult,omitempty"`
PrevResult *current.Result `json:"-"`
Mac string `json:"mac,omitempty"`
Promisc bool `json:"promisc,omitempty"`
Mtu int `json:"mtu,omitempty"`
}
func parseConf(data []byte) (*TuningConf, error) {
conf := TuningConf{}
type MACEnvArgs struct {
types.CommonArgs
MAC types.UnmarshallableString `json:"mac,omitempty"`
}
func parseConf(data []byte, envArgs string) (*TuningConf, error) {
conf := TuningConf{Promisc: false}
if err := json.Unmarshal(data, &conf); err != nil {
return nil, fmt.Errorf("failed to load netconf: %v", err)
}
// Parse custom MAC from both env args
if envArgs != "" {
e := MACEnvArgs{}
err := types.LoadArgs(envArgs, &e)
if err != nil {
return nil, err
}
if e.MAC != "" {
conf.Mac = string(e.MAC)
}
}
// Parse previous result.
if conf.RawPrevResult != nil {
resultBytes, err := json.Marshal(conf.RawPrevResult)
@@ -65,8 +88,58 @@ func parseConf(data []byte) (*TuningConf, error) {
return &conf, nil
}
func changeMacAddr(ifName string, newMacAddr string) error {
addr, err := net.ParseMAC(newMacAddr)
if err != nil {
return fmt.Errorf("invalid args %v for MAC addr: %v", newMacAddr, err)
}
link, err := netlink.LinkByName(ifName)
if err != nil {
return fmt.Errorf("failed to get %q: %v", ifName, err)
}
err = netlink.LinkSetDown(link)
if err != nil {
return fmt.Errorf("failed to set %q down: %v", ifName, err)
}
err = netlink.LinkSetHardwareAddr(link, addr)
if err != nil {
return fmt.Errorf("failed to set %q address to %q: %v", ifName, newMacAddr, err)
}
return netlink.LinkSetUp(link)
}
func updateResultsMacAddr(config TuningConf, ifName string, newMacAddr string) {
for _, i := range config.PrevResult.Interfaces {
if i.Name == ifName {
i.Mac = newMacAddr
}
}
}
func changePromisc(ifName string, val bool) error {
link, err := netlink.LinkByName(ifName)
if err != nil {
return fmt.Errorf("failed to get %q: %v", ifName, err)
}
if val {
return netlink.SetPromiscOn(link)
}
return netlink.SetPromiscOff(link)
}
func changeMtu(ifName string, mtu int) error {
link, err := netlink.LinkByName(ifName)
if err != nil {
return fmt.Errorf("failed to get %q: %v", ifName, err)
}
return netlink.LinkSetMTU(link, mtu)
}
func cmdAdd(args *skel.CmdArgs) error {
tuningConf, err := parseConf(args.StdinData)
tuningConf, err := parseConf(args.StdinData, args.Args)
if err != nil {
return err
}
@@ -90,6 +163,25 @@ func cmdAdd(args *skel.CmdArgs) error {
return err
}
}
if tuningConf.Mac != "" {
if err = changeMacAddr(args.IfName, tuningConf.Mac); err != nil {
return err
}
updateResultsMacAddr(*tuningConf, args.IfName, tuningConf.Mac)
}
if tuningConf.Promisc != false {
if err = changePromisc(args.IfName, true); err != nil {
return err
}
}
if tuningConf.Mtu != 0 {
if err = changeMtu(args.IfName, tuningConf.Mtu); err != nil {
return err
}
}
return nil
})
if err != nil {
@@ -107,5 +199,11 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.All)
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}

View File

@@ -19,6 +19,7 @@ import (
"github.com/containernetworking/cni/pkg/types/current"
"github.com/containernetworking/plugins/pkg/ns"
"github.com/containernetworking/plugins/pkg/testutils"
"net"
"github.com/vishvananda/netlink"
@@ -109,4 +110,236 @@ var _ = Describe("tuning plugin", func() {
})
Expect(err).NotTo(HaveOccurred())
})
It("configures and deconfigures promiscas mode with ADD/DEL", func() {
conf := []byte(`{
"name": "test",
"type": "iplink",
"cniVersion": "0.3.1",
"promisc": true,
"prevResult": {
"interfaces": [
{"name": "dummy0", "sandbox":"netns"}
],
"ips": [
{
"version": "4",
"address": "10.0.0.2/24",
"gateway": "10.0.0.1",
"interface": 0
}
]
}
}`)
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: originalNS.Path(),
IfName: IFNAME,
StdinData: conf,
}
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
r, _, err := testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
result, err := current.GetResult(r)
Expect(err).NotTo(HaveOccurred())
Expect(len(result.Interfaces)).To(Equal(1))
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
Expect(len(result.IPs)).To(Equal(1))
Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
link, err := netlink.LinkByName(IFNAME)
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().Promisc).To(Equal(1))
err = testutils.CmdDel(originalNS.Path(),
args.ContainerID, "", func() error { return cmdDel(args) })
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())
})
It("configures and deconfigures mtu with ADD/DEL", func() {
conf := []byte(`{
"name": "test",
"type": "iplink",
"cniVersion": "0.3.1",
"mtu": 1454,
"prevResult": {
"interfaces": [
{"name": "dummy0", "sandbox":"netns"}
],
"ips": [
{
"version": "4",
"address": "10.0.0.2/24",
"gateway": "10.0.0.1",
"interface": 0
}
]
}
}`)
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: originalNS.Path(),
IfName: IFNAME,
StdinData: conf,
}
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
r, _, err := testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
result, err := current.GetResult(r)
Expect(err).NotTo(HaveOccurred())
Expect(len(result.Interfaces)).To(Equal(1))
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
Expect(len(result.IPs)).To(Equal(1))
Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
link, err := netlink.LinkByName(IFNAME)
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().MTU).To(Equal(1454))
err = testutils.CmdDel(originalNS.Path(),
args.ContainerID, "", func() error { return cmdDel(args) })
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())
})
It("configures and deconfigures mac address (from conf file) with ADD/DEL", func() {
conf := []byte(`{
"name": "test",
"type": "iplink",
"cniVersion": "0.3.1",
"mac": "c2:11:22:33:44:55",
"prevResult": {
"interfaces": [
{"name": "dummy0", "sandbox":"netns"}
],
"ips": [
{
"version": "4",
"address": "10.0.0.2/24",
"gateway": "10.0.0.1",
"interface": 0
}
]
}
}`)
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: originalNS.Path(),
IfName: IFNAME,
StdinData: conf,
}
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
r, _, err := testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
result, err := current.GetResult(r)
Expect(err).NotTo(HaveOccurred())
Expect(len(result.Interfaces)).To(Equal(1))
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
Expect(len(result.IPs)).To(Equal(1))
Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
link, err := netlink.LinkByName(IFNAME)
Expect(err).NotTo(HaveOccurred())
hw, err := net.ParseMAC("c2:11:22:33:44:55")
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().HardwareAddr).To(Equal(hw))
err = testutils.CmdDel(originalNS.Path(),
args.ContainerID, "", func() error { return cmdDel(args) })
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())
})
It("configures and deconfigures mac address (from CNI_ARGS) with ADD/DEL", func() {
conf := []byte(`{
"name": "test",
"type": "iplink",
"cniVersion": "0.3.1",
"prevResult": {
"interfaces": [
{"name": "dummy0", "sandbox":"netns"}
],
"ips": [
{
"version": "4",
"address": "10.0.0.2/24",
"gateway": "10.0.0.1",
"interface": 0
}
]
}
}`)
args := &skel.CmdArgs{
ContainerID: "dummy",
Netns: originalNS.Path(),
IfName: IFNAME,
StdinData: conf,
Args: "IgnoreUnknown=true;MAC=c2:11:22:33:44:66",
}
err := originalNS.Do(func(ns.NetNS) error {
defer GinkgoRecover()
r, _, err := testutils.CmdAddWithArgs(args, func() error {
return cmdAdd(args)
})
Expect(err).NotTo(HaveOccurred())
result, err := current.GetResult(r)
Expect(err).NotTo(HaveOccurred())
Expect(len(result.Interfaces)).To(Equal(1))
Expect(result.Interfaces[0].Name).To(Equal(IFNAME))
Expect(len(result.IPs)).To(Equal(1))
Expect(result.IPs[0].Address.String()).To(Equal("10.0.0.2/24"))
link, err := netlink.LinkByName(IFNAME)
Expect(err).NotTo(HaveOccurred())
hw, err := net.ParseMAC("c2:11:22:33:44:66")
Expect(err).NotTo(HaveOccurred())
Expect(link.Attrs().HardwareAddr).To(Equal(hw))
err = testutils.CmdDel(originalNS.Path(),
args.ContainerID, "", func() error { return cmdDel(args) })
Expect(err).NotTo(HaveOccurred())
return nil
})
Expect(err).NotTo(HaveOccurred())
})
})

View File

@@ -141,5 +141,11 @@ func cmdDel(args *skel.CmdArgs) error {
}
func main() {
skel.PluginMain(cmdAdd, cmdDel, version.PluginSupports("", "0.1.0", "0.2.0", version.Current()))
// TODO: implement plugin version
skel.PluginMain(cmdAdd, cmdGet, cmdDel, version.All, "TODO")
}
func cmdGet(args *skel.CmdArgs) error {
// TODO: implement
return fmt.Errorf("not implemented")
}