Skip to content

Commit 1aeabaf

Browse files
yunchenchenyunchen
yunchen
authored andcommitted
Add port setting options
1 parent 813765f commit 1aeabaf

File tree

3 files changed

+182
-0
lines changed

3 files changed

+182
-0
lines changed

.travis.yml

+1
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ before_install:
99
- sudo apt install openvswitch-switch
1010
- sudo ovs-vsctl add-br ovsbr0
1111
- go get github.com/golang/lint/golint
12+
- go get github.com/google/go-cmp/cmp
1213
- go get honnef.co/go/tools/cmd/staticcheck
1314
- go get -d ./...
1415
script:

ovs/vswitch.go

+85
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ package ovs
1717
import (
1818
"encoding/json"
1919
"fmt"
20+
"strconv"
2021
"strings"
2122
)
2223

@@ -179,6 +180,47 @@ func (v *VSwitchGetService) Bridge(bridge string) (BridgeOptions, error) {
179180
}, nil
180181
}
181182

183+
// Port gets configuration for a port and returns the values through
184+
// a PortOptions struct.
185+
func (v *VSwitchGetService) Port(port string) (PortOptions, error) {
186+
// We only support the tag, vlan_mode, trunk option at this point.
187+
args := []string{"--format=json", "get", "port", port, "tag", "vlan_mode", "trunk"}
188+
out, err := v.v.exec(args...)
189+
if err != nil {
190+
return PortOptions{}, err
191+
}
192+
193+
// If the option is not exist, OVS will return "[]\n"
194+
options := strings.Split(strings.TrimSpace(string(out)), "\n")
195+
196+
var tag *int
197+
if options[0] != "[]" {
198+
tagNum, err := strconv.Atoi(options[0])
199+
if err != nil {
200+
return PortOptions{}, err
201+
}
202+
tag = &tagNum
203+
}
204+
205+
var vlanMode *string
206+
if options[1] != "[]" {
207+
vlanMode = &options[1]
208+
}
209+
210+
var trunk []int
211+
if options[2] != "[]" {
212+
if err := json.Unmarshal([]byte(options[2]), &trunk); err != nil {
213+
return PortOptions{}, err
214+
}
215+
}
216+
217+
return PortOptions{
218+
Tag: tag,
219+
VLANMode: vlanMode,
220+
Trunk: trunk,
221+
}, nil
222+
}
223+
182224
// A VSwitchSetService is used in a VSwitchService to execute 'ovs-vsctl set'
183225
// subcommands.
184226
type VSwitchSetService struct {
@@ -216,6 +258,49 @@ func (o BridgeOptions) slice() []string {
216258
return s
217259
}
218260

261+
// Port sets configuration for a port using the values from a PortOptions
262+
// struct.
263+
func (v *VSwitchSetService) Port(port string, options PortOptions) error {
264+
// Prepend command line arguments before expanding options slice
265+
// and appending it
266+
args := []string{"set", "port", port}
267+
args = append(args, options.slice()...)
268+
269+
_, err := v.v.exec(args...)
270+
return err
271+
}
272+
273+
// An PortOptions struct enables configuration of a port.
274+
type PortOptions struct {
275+
Tag *int
276+
VLANMode *string
277+
Trunk []int
278+
}
279+
280+
// slice creates a string slice containing any non-zero option values from the
281+
// struct in the format expected by Open vSwitch.
282+
func (o PortOptions) slice() []string {
283+
var s []string
284+
285+
if o.Tag != nil {
286+
s = append(s, fmt.Sprintf("tag=%p,", o.Tag))
287+
}
288+
289+
if o.VLANMode != nil {
290+
s = append(s, fmt.Sprintf("vlan_mode=%p", o.VLANMode))
291+
}
292+
293+
if len(o.Trunk) > 0 {
294+
var strTrunk string
295+
for _, trunk := range o.Trunk {
296+
strTrunk += fmt.Sprintf("%s,", strconv.Itoa(int(trunk)))
297+
}
298+
s = append(s, fmt.Sprintf("trunk=%s", strTrunk))
299+
}
300+
301+
return s
302+
}
303+
219304
// Interface sets configuration for an interface using the values from an
220305
// InterfaceOptions struct.
221306
func (v *VSwitchSetService) Interface(ifi string, options InterfaceOptions) error {

ovs/vswitch_test.go

+96
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"errors"
2020
"fmt"
2121
"reflect"
22+
"strconv"
2223
"strings"
2324
"testing"
2425
)
@@ -501,6 +502,101 @@ func TestClientVSwitchSetBridgeProtocolsOK(t *testing.T) {
501502
}
502503
}
503504

505+
func TestClientVSwitchGetPortOptionsOK(t *testing.T) {
506+
const port = "bond0"
507+
vlanModeStr := "trunk"
508+
vlanMode := &vlanModeStr
509+
trunk := []int{1, 2, 3, 4, 5}
510+
511+
c := testClient([]OptionFunc{Timeout(1)}, func(cmd string, args ...string) ([]byte, error) {
512+
if want, got := "ovs-vsctl", cmd; want != got {
513+
t.Fatalf("incorrect command:\n- want: %v\n- got: %v",
514+
want, got)
515+
}
516+
517+
wantArgs := []string{
518+
"--timeout=1",
519+
"--format=json",
520+
"get",
521+
"port",
522+
port,
523+
"tag",
524+
"vlan_mode",
525+
"trunk",
526+
}
527+
if want, got := wantArgs, args; !reflect.DeepEqual(want, got) {
528+
t.Fatalf("incorrect arguments\n- want: %v\n- got: %v",
529+
want, got)
530+
}
531+
532+
// Make the return value with newline to simulate
533+
// the ovs-vsctl output.
534+
data := "[]\n"
535+
data += fmt.Sprintf("%s\n", vlanModeStr)
536+
t, err := json.Marshal(&trunk)
537+
if err != nil {
538+
return nil, err
539+
}
540+
data += fmt.Sprintf("%s\n", string(t))
541+
return []byte(fmt.Sprintln(data)), err
542+
})
543+
544+
got, err := c.VSwitch.Get.Port(port)
545+
if err != nil {
546+
t.Fatalf("unexpected error for Client.VSwitch.Get.Port: %v", err)
547+
}
548+
if got.Tag != nil {
549+
t.Fatalf("unexpected tag for Client.VSwitch.Get.Port: %v", *got.Tag)
550+
}
551+
if !reflect.DeepEqual(*got.VLANMode, *vlanMode) {
552+
t.Fatalf("unexpected vlan_mode for Client.VSwitch.Get.Port: %v", *got.VLANMode)
553+
}
554+
if !reflect.DeepEqual(got.Trunk, trunk) {
555+
t.Fatalf("unexpected trunk for Client.VSwitch.Get.Port: %v", got.Trunk)
556+
}
557+
}
558+
559+
func TestClientVSwitchSetPortOptionsOK(t *testing.T) {
560+
const port = "bond0"
561+
vlanModeStr := "trunk"
562+
vlanMode := &vlanModeStr
563+
trunk := []int{1, 2, 3, 4, 5}
564+
565+
c := testClient([]OptionFunc{Timeout(1)}, func(cmd string, args ...string) ([]byte, error) {
566+
if want, got := "ovs-vsctl", cmd; want != got {
567+
t.Fatalf("incorrect command:\n- want: %v\n- got: %v",
568+
want, got)
569+
}
570+
571+
var trunkSequence string
572+
for _, trunk := range trunk {
573+
trunkSequence += fmt.Sprintf("%s,", strconv.Itoa(int(trunk)))
574+
}
575+
wantArgs := []string{
576+
"--timeout=1",
577+
"set",
578+
"port",
579+
port,
580+
fmt.Sprintf("vlan_mode=%p", vlanMode),
581+
fmt.Sprintf("trunk=%s", trunkSequence),
582+
}
583+
if want, got := wantArgs, args; !reflect.DeepEqual(want, got) {
584+
t.Fatalf("incorrect arguments\n- want: %v\n- got: %v",
585+
want, got)
586+
}
587+
588+
return nil, nil
589+
})
590+
591+
err := c.VSwitch.Set.Port(port, PortOptions{
592+
VLANMode: vlanMode,
593+
Trunk: trunk,
594+
})
595+
if err != nil {
596+
t.Fatalf("unexpected error for Client.VSwitch.Set.Bridge: %v", err)
597+
}
598+
}
599+
504600
func TestClientVSwitchSetInterfaceTypeOK(t *testing.T) {
505601
ifi := "bond0"
506602
ifiType := InterfaceTypePatch

0 commit comments

Comments
 (0)