Skip to content

Commit

Permalink
Merge pull request #8 from hustcat/devel
Browse files Browse the repository at this point in the history
Move 'VF/MAC/VLAN' from NetConf to NetArgs by following the CNI spec
  • Loading branch information
hustcat authored Mar 14, 2017
2 parents 7bd3ac8 + ca774bf commit caed171
Show file tree
Hide file tree
Showing 7 changed files with 247 additions and 38 deletions.
37 changes: 28 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,13 @@ options ixgbe max_vfs=8,8
* `name` (string, required): the name of the network
* `type` (string, required): "sriov"
* `master` (string, required): name of the PF
* `ipam` (dictionary, required): IPAM configuration to be used for this network.

## Extra arguments

* `vf` (int, optional): VF index, default value is 0
* `vlan` (int, optional): VLAN ID for VF device
* `mac` (string, optional): mac address for VF device
* `ipam` (dictionary, required): IPAM configuration to be used for this network.

## Usage

Expand All @@ -45,10 +48,8 @@ Given the following network configuration:
"name": "mynet",
"type": "sriov",
"master": "eth1",
"vf": 1,
"mac": "66:d8:02:77:aa:aa",
"ipam": {
"type": "host-local",
"type": "fixipam",
"subnet": "10.55.206.0/26",
"routes": [
{ "dst": "0.0.0.0/0" }
Expand All @@ -59,16 +60,22 @@ Given the following network configuration:
EOF
```

```
# CNI_PATH=$CNI_PATH CNI_ARGS="IP=10.55.206.46" ./priv-net-run.sh ifconfig
Add container to network:

```sh
# CNI_PATH=`pwd`/bin
# cd scripts
# CNI_PATH=$CNI_PATH CNI_ARGS="IP=10.55.206.46;VF=1;MAC=66:d8:02:77:aa:aa" ./priv-net-run.sh ifconfig
contid=148e21a85bcc7aaf
netnspath=/var/run/netns/148e21a85bcc7aaf
eth0 Link encap:Ethernet HWaddr 66:D8:02:77:AA:AA
inet addr:10.55.206.46 Bcast:0.0.0.0 Mask:255.255.255.192
inet6 addr: fe80::64d8:2ff:fe77:aaaa/64 Scope:Link
UP BROADCAST RUNNING MULTICAST MTU:1500 Metric:1
RX packets:7 errors:0 dropped:0 overruns:0 frame:0
TX packets:14 errors:0 dropped:0 overruns:0 carrier:0
RX packets:0 errors:0 dropped:0 overruns:0 frame:0
TX packets:7 errors:0 dropped:0 overruns:0 carrier:0
collisions:0 txqueuelen:1000
RX bytes:530 (530.0 b) TX bytes:988 (988.0 b)
RX bytes:0 (0.0 b) TX bytes:558 (558.0 b)

lo Link encap:Local Loopback
inet addr:127.0.0.1 Mask:255.0.0.0
Expand All @@ -80,4 +87,16 @@ lo Link encap:Local Loopback
RX bytes:0 (0.0 b) TX bytes:0 (0.0 b)
```

Remove container from network:

```sh
# CNI_PATH=$CNI_PATH ./exec-plugins.sh del $contid /var/run/netns/$contid
```

For example:

```sh
# CNI_PATH=$CNI_PATH ./exec-plugins.sh del 148e21a85bcc7aaf /var/run/netns/148e21a85bcc7aaf
```

[More info](https://github.com/containernetworking/cni/pull/259).
101 changes: 101 additions & 0 deletions config/args.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
package config

import (
"encoding"
"fmt"
"reflect"
"strconv"
"strings"
)

// UnmarshallableBool typedef for builtin bool
// because builtin type's methods can't be declared
type UnmarshallableBool bool

// UnmarshalText implements the encoding.TextUnmarshaler interface.
// Returns boolean true if the string is "1" or "[Tt]rue"
// Returns boolean false if the string is "0" or "[Ff]alse"
func (b *UnmarshallableBool) UnmarshalText(data []byte) error {
s := strings.ToLower(string(data))
switch s {
case "1", "true":
*b = true
case "0", "false":
*b = false
default:
return fmt.Errorf("Boolean unmarshal error: invalid input %s", s)
}
return nil
}

// UnmarshallableString typedef for builtin string
type UnmarshallableString string

// UnmarshalText implements the encoding.TextUnmarshaler interface.
// Returns the string
func (s *UnmarshallableString) UnmarshalText(data []byte) error {
*s = UnmarshallableString(data)
return nil
}

// CommonArgs contains the IgnoreUnknown argument
// and must be embedded by all Arg structs
type CommonArgs struct {
IgnoreUnknown UnmarshallableBool `json:"ignoreunknown,omitempty"`
}

// GetKeyField is a helper function to receive Values
// Values that represent a pointer to a struct
func GetKeyField(keyString string, v reflect.Value) reflect.Value {
return v.Elem().FieldByName(keyString)
}

// LoadSriovArgs parses args from a string in the form "K=V;K2=V2;..."
func LoadSriovArgs(args string, container interface{}) error {
if args == "" {
return nil
}

containerValue := reflect.ValueOf(container)

pairs := strings.Split(args, ";")
unknownArgs := []string{}
for _, pair := range pairs {
kv := strings.Split(pair, "=")
if len(kv) != 2 {
return fmt.Errorf("ARGS: invalid pair %q", pair)
}
keyString := kv[0]
valueString := kv[1]
keyField := GetKeyField(keyString, containerValue)
if !keyField.IsValid() {
unknownArgs = append(unknownArgs, pair)
continue
}

switch keyField.Kind() {
case reflect.Int:
vi, err := strconv.Atoi(valueString)
if err != nil {
return fmt.Errorf("Convert value %s for field %s failed", valueString, keyString)
}
keyField.SetInt(int64(vi))
case reflect.String:
keyField.SetString(valueString)
case reflect.Slice:
u := keyField.Addr().Interface().(encoding.TextUnmarshaler)
err := u.UnmarshalText([]byte(valueString))
if err != nil {
return fmt.Errorf("ARGS: error parsing value of pair %q: %v)", pair, err)
}
default:
return fmt.Errorf("Unsupport type %s for %s", keyField.Kind().String(), keyString)
}
}

isIgnoreUnknown := GetKeyField("IgnoreUnknown", containerValue).Bool()
if len(unknownArgs) > 0 && !isIgnoreUnknown {
return fmt.Errorf("ARGS: unknown args %q", unknownArgs)
}
return nil
}
30 changes: 30 additions & 0 deletions config/args_test.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package config

import (
"testing"
)

func TestLoadArgs(t *testing.T) {
s := "VF=1;VLAN=10;MAC=AA:BB:CC:DD:EE:FF;IP=192.168.1.2"
args := &NetArgs{}
err := LoadSriovArgs(s, args)
if err != nil {
t.Errorf("error %v", err)
}
if args.IP.String() != "192.168.1.2" {
t.Errorf("failed to parse IP")
}
if args.VF != 1 {
t.Errorf("failed to parse VF")
}
if args.MAC != "AA:BB:CC:DD:EE:FF" {
t.Errorf("failed to parse MAC")
}
if args.VLAN != 10 {
t.Errorf("failed to parse VLAN")
}

//fmt.Printf("%#v\n%s\n", args, args.IP.String())
}

// go test -run LoadArgs
25 changes: 25 additions & 0 deletions config/config.go
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package config

import (
"net"

"github.com/containernetworking/cni/pkg/types"
)

type NetConf struct {
types.NetConf
Master string `json:"master"`
}

type NetArgs struct {
types.CommonArgs
VF int `json:"vf,omitempty"`
VLAN int `json:"vlan,omitempty"`
MAC string `json:"mac,omitempty"`
IP net.IP `json:"ip,omitempty"`
}

type SriovConf struct {
Net *NetConf
Args *NetArgs
}
3 changes: 2 additions & 1 deletion fixipam/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,10 @@ package main

import (
"fmt"
"net"

"github.com/containernetworking/cni/pkg/skel"
"github.com/containernetworking/cni/pkg/types"
"net"
)

func main() {
Expand Down
3 changes: 3 additions & 0 deletions scripts/priv-net-run.sh
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,10 @@ if [[ ${DEBUG} -gt 0 ]]; then set -x; fi
# Run a command in a private network namespace
# set up by CNI plugins
contid=$(printf '%x%x%x%x' $RANDOM $RANDOM $RANDOM $RANDOM)
echo "contid=$contid"

netnspath=/var/run/netns/$contid
echo "netnspath=$netnspath"

ip netns add $contid
./exec-plugins.sh add $contid $netnspath
Expand Down
Loading

0 comments on commit caed171

Please sign in to comment.