Skip to content

Commit f7b6758

Browse files
author
Joji Mekkatt
authored
Merge pull request contiv#680 from DivyaVavili/upd-mbr-links
upgrade uplink changes
2 parents 9ca4087 + e06897f commit f7b6758

9 files changed

+256
-22
lines changed

drivers/ovsSwitch.go

+86-19
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,8 @@ import (
1919
"errors"
2020
"fmt"
2121
"net"
22+
"reflect"
23+
"sort"
2224
"strings"
2325
"time"
2426

@@ -572,6 +574,55 @@ func (sw *OvsSwitch) DeleteVtep(vtepIP string) error {
572574
return sw.ovsdbDriver.DeleteVtep(intfName)
573575
}
574576

577+
func (sw *OvsSwitch) cleanupOldUplinkState(portName string, intfList []string) (bool, error) {
578+
var err error
579+
var oldUplinkIntf []string
580+
portCreateReq := true
581+
582+
// Check if uplink is already created
583+
// Case 1: Bonded ports - port name is the uplinkName
584+
// Case 2: Indiviual port - port name is the interface name
585+
portPresent := sw.ovsdbDriver.IsPortNamePresent(portName)
586+
if portPresent {
587+
/* If port already exists, make sure it has the same member links
588+
If not, a cleanup is required */
589+
sort.Strings(intfList)
590+
oldUplinkIntf = sw.ovsdbDriver.GetInterfacesInPort(portName)
591+
if reflect.DeepEqual(intfList, oldUplinkIntf) {
592+
log.Warnf("Uplink already part of %s", sw.bridgeName)
593+
portCreateReq = false
594+
} else {
595+
log.Warnf("Deleting old uplink bond with intfs: %+v", oldUplinkIntf)
596+
err = sw.ovsdbDriver.DeletePortBond(portName, oldUplinkIntf)
597+
if err == nil {
598+
portCreateReq = true
599+
}
600+
}
601+
return portCreateReq, err
602+
}
603+
604+
if len(intfList) == 1 && sw.ovsdbDriver.IsPortNamePresent(intfList[0]) {
605+
// Uplink port already part of switch. No change required.
606+
log.Debugf("Uplink intf %s already part of %s", intfList[0], sw.bridgeName)
607+
return false, nil
608+
}
609+
610+
/* Cleanup any other individual ports that may exist */
611+
for _, intf := range intfList {
612+
if sw.ovsdbDriver.IsIntfNamePresent(intf) {
613+
log.Infof("Deleting old uplink port: %+v", intf)
614+
err = sw.ovsdbDriver.DeletePort(intf)
615+
if err != nil {
616+
break
617+
}
618+
portCreateReq = true
619+
}
620+
}
621+
622+
// No cleanup done and new port creation required
623+
return portCreateReq, err
624+
}
625+
575626
// AddUplink adds uplink port(s) to the OVS
576627
func (sw *OvsSwitch) AddUplink(uplinkName string, intfList []string) error {
577628
var err error
@@ -583,16 +634,23 @@ func (sw *OvsSwitch) AddUplink(uplinkName string, intfList []string) error {
583634
log.Fatalf("Can not add uplink to OVS type %s.", sw.netType)
584635
}
585636

586-
// Check if port is already part of the OVS and add it
587-
if !sw.ovsdbDriver.IsPortNamePresent(uplinkName) {
637+
createUplink, err := sw.cleanupOldUplinkState(uplinkName, intfList)
638+
if err != nil {
639+
log.Errorf("Could not cleanup previous uplink state")
640+
return err
641+
}
642+
643+
if createUplink {
588644
if len(intfList) > 1 {
645+
log.Debugf("Creating uplink port bond: %s with intf: %+v", uplinkName, intfList)
589646
err = sw.ovsdbDriver.CreatePortBond(intfList, uplinkName)
590647
if err != nil {
591648
log.Errorf("Error adding uplink %s to OVS. Err: %v", intfList, err)
592649
return err
593650
}
594651
uplinkType = ofnet.BondType
595652
} else {
653+
log.Debugf("Creating uplink port: %s", intfList[0])
596654
// Ask OVSDB driver to add the port as a trunk port
597655
err = sw.ovsdbDriver.CreatePort(intfList[0], "", uplinkName, 0, 0, 0)
598656
if err != nil {
@@ -601,14 +659,14 @@ func (sw *OvsSwitch) AddUplink(uplinkName string, intfList []string) error {
601659
}
602660
uplinkType = ofnet.PortType
603661
}
604-
}
605662

606-
// HACK: When an uplink is added to OVS, it disconnects the controller connection.
607-
// This is a hack to workaround this issue. We wait for the OVS to reconnect
608-
// to the controller.
609-
// Wait for a while for OVS switch to disconnect/connect to ofnet agent
610-
time.Sleep(time.Second)
611-
sw.ofnetAgent.WaitForSwitchConnection()
663+
// HACK: When an uplink is added to OVS, it disconnects the controller connection.
664+
// This is a hack to workaround this issue. We wait for the OVS to reconnect
665+
// to the controller.
666+
// Wait for a while for OVS switch to disconnect/connect to ofnet agent
667+
time.Sleep(time.Second)
668+
sw.ofnetAgent.WaitForSwitchConnection()
669+
}
612670

613671
uplinkInfo := ofnet.PortInfo{
614672
Name: uplinkName,
@@ -686,16 +744,31 @@ func (sw *OvsSwitch) HandleLinkUpdates(linkUpd ofnet.LinkUpdateInfo) {
686744
func (sw *OvsSwitch) RemoveUplinks() error {
687745

688746
var err error
747+
689748
// some error checking
690749
if sw.netType != "vlan" {
691750
log.Fatalf("Can not remove uplink from OVS type %s.", sw.netType)
692751
}
752+
693753
for intfListObj := range sw.uplinkDb.IterBuffered() {
694754
intfList := intfListObj.Val.([]string)
695755
portName := intfListObj.Key
696-
if !sw.ovsdbDriver.IsPortNamePresent(portName) {
756+
757+
// Remove uplink from agent
758+
err = sw.ofnetAgent.RemoveUplink(portName)
759+
if err != nil {
760+
log.Errorf("Error removing uplink %s. Err: %v", portName, err)
761+
return err
762+
}
763+
log.Infof("Removed uplink %s from ofnet", portName)
764+
765+
isPortPresent := sw.ovsdbDriver.IsPortNamePresent(portName)
766+
if len(intfList) == 1 {
767+
isPortPresent = sw.ovsdbDriver.IsPortNamePresent(intfList[0])
768+
}
769+
if isPortPresent {
697770
if len(intfList) == 1 {
698-
err = sw.ovsdbDriver.DeletePort(portName)
771+
err = sw.ovsdbDriver.DeletePort(intfList[0])
699772
} else {
700773
err = sw.ovsdbDriver.DeletePortBond(portName, intfList)
701774
}
@@ -705,17 +778,11 @@ func (sw *OvsSwitch) RemoveUplinks() error {
705778
}
706779
}
707780
time.Sleep(time.Second)
708-
709-
// Remove uplink from agent
710-
err = sw.ofnetAgent.RemoveUplink(portName)
711-
if err != nil {
712-
log.Errorf("Error removing uplink %s. Err: %v", portName, err)
713-
return err
714-
}
715781
sw.uplinkDb.Remove(portName)
716782

717-
log.Infof("Removed uplink %s from OVS switch %s.", portName, sw.bridgeName)
783+
log.Infof("Removed uplink %s(%+v) from OVS switch %s.", portName, intfList, sw.bridgeName)
718784
}
785+
719786
return nil
720787
}
721788

drivers/ovsdbDriver.go

+78-1
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@ import (
1919
"errors"
2020
"fmt"
2121
"reflect"
22+
"sort"
2223
"sync"
2324
"time"
2425

@@ -370,6 +371,57 @@ func (d *OvsdbDriver) CreatePort(intfName, intfType, id string, tag, burst int,
370371
return d.performOvsdbOps(operations)
371372
}
372373

374+
// GetInterfacesInPort gets list of interfaces in a port in sorted order
375+
func (d *OvsdbDriver) GetInterfacesInPort(portName string) []string {
376+
var intfList []string
377+
d.cacheLock.RLock()
378+
defer d.cacheLock.RUnlock()
379+
380+
for _, row := range d.cache["Port"] {
381+
name := row.Fields["name"].(string)
382+
if name == portName {
383+
// Port found
384+
// Iterate over the list of interfaces
385+
switch (row.Fields["interfaces"]).(type) {
386+
case libovsdb.UUID: // Individual interface case
387+
intfUUID := row.Fields["interfaces"].(libovsdb.UUID)
388+
intfInfo := d.GetIntfInfo(intfUUID)
389+
if reflect.DeepEqual(intfInfo, libovsdb.Row{}) {
390+
log.Errorf("could not find interface with UUID: %+v", intfUUID)
391+
break
392+
}
393+
intfList = append(intfList, intfInfo.Fields["name"].(string))
394+
case libovsdb.OvsSet: // Port bond case
395+
intfUUIDList := row.Fields["interfaces"].(libovsdb.OvsSet)
396+
for _, intfUUID := range intfUUIDList.GoSet {
397+
intfInfo := d.GetIntfInfo(intfUUID.(libovsdb.UUID))
398+
if reflect.DeepEqual(intfInfo, libovsdb.Row{}) {
399+
continue
400+
}
401+
intfList = append(intfList, intfInfo.Fields["name"].(string))
402+
}
403+
}
404+
sort.Strings(intfList)
405+
break
406+
}
407+
}
408+
return intfList
409+
}
410+
411+
// GetIntfInfo gets interface information from "Interface" table
412+
func (d *OvsdbDriver) GetIntfInfo(uuid libovsdb.UUID) libovsdb.Row {
413+
d.cacheLock.RLock()
414+
defer d.cacheLock.RUnlock()
415+
416+
for intfUUID, row := range d.cache["Interface"] {
417+
if intfUUID == uuid {
418+
return row
419+
}
420+
}
421+
422+
return libovsdb.Row{}
423+
}
424+
373425
//CreatePortBond creates port bond in OVS
374426
func (d *OvsdbDriver) CreatePortBond(intfList []string, bondName string) error {
375427

@@ -720,13 +772,38 @@ func (d *OvsdbDriver) IsControllerPresent(target string) bool {
720772
}
721773

722774
// IsPortNamePresent checks if port already exists in OVS bridge
723-
func (d *OvsdbDriver) IsPortNamePresent(intfName string) bool {
775+
func (d *OvsdbDriver) IsPortNamePresent(portName string) bool {
724776
d.cacheLock.RLock()
725777
defer d.cacheLock.RUnlock()
726778

727779
// walk the local cache
728780
for tName, table := range d.cache {
729781
if tName == "Port" {
782+
for _, row := range table {
783+
for fieldName, value := range row.Fields {
784+
if fieldName == "name" {
785+
if value == portName {
786+
// Port name exists.
787+
return true
788+
}
789+
}
790+
}
791+
}
792+
}
793+
}
794+
795+
// We could not find the port name
796+
return false
797+
}
798+
799+
// IsIntfNamePresent checks if intf already exists in OVS bridge
800+
func (d *OvsdbDriver) IsIntfNamePresent(intfName string) bool {
801+
d.cacheLock.RLock()
802+
defer d.cacheLock.RUnlock()
803+
804+
// walk the local cache
805+
for tName, table := range d.cache {
806+
if tName == "Interface" {
730807
for _, row := range table {
731808
for fieldName, value := range row.Fields {
732809
if fieldName == "name" {

drivers/ovsdriver.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,7 @@ func (d *OvsDriver) Init(info *core.InstanceInfo) error {
190190

191191
// Add uplink to VLAN switch
192192
if len(info.UplinkIntf) != 0 {
193-
err = d.switchDb["vlan"].AddUplink("uplinkBond", info.UplinkIntf)
193+
err = d.switchDb["vlan"].AddUplink("uplinkPort", info.UplinkIntf)
194194
if err != nil {
195195
log.Errorf("Could not add uplink %v to vlan OVS. Err: %v", info.UplinkIntf, err)
196196
}

drivers/ovsdriver_test.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ func TestOvsDriverUplinkBridgeMode(t *testing.T) {
518518
t.Fatalf("Could not add uplink %+v to vlan OVS. Err: %v", uplinkPorts, err)
519519
}
520520

521-
time.Sleep(300 * time.Millisecond)
521+
time.Sleep(time.Second)
522522

523523
// verify uplink port
524524
output, err := exec.Command("ovs-vsctl", "list", "Port").CombinedOutput()

test/systemtests/docker_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -468,6 +468,7 @@ func (d *docker) cleanupSlave() {
468468
vNode := d.node.tbnode
469469
vNode.RunCommand("sudo ovs-vsctl del-br contivVxlanBridge")
470470
vNode.RunCommand("sudo ovs-vsctl del-br contivVlanBridge")
471+
vNode.RunCommand("sudo ovs-vsctl del-br contivHostBridge")
471472
vNode.RunCommand("for p in `ifconfig | grep vport | awk '{print $1}'`; do sudo ip link delete $p type veth; done")
472473
vNode.RunCommand("sudo rm /var/run/docker/plugins/netplugin.sock")
473474
vNode.RunCommand("sudo service docker restart")

test/systemtests/k8setup_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -486,6 +486,7 @@ func (k *kubernetes) cleanupSlave() {
486486
vNode := k.node.tbnode
487487
vNode.RunCommand("sudo ovs-vsctl del-br contivVxlanBridge")
488488
vNode.RunCommand("sudo ovs-vsctl del-br contivVlanBridge")
489+
vNode.RunCommand("sudo ovs-vsctl del-br contivHostBridge")
489490
vNode.RunCommand("for p in `ifconfig | grep vport | awk '{print $1}'`; do sudo ip link delete $p type veth; done")
490491
vNode.RunCommand("sudo rm /var/run/docker/plugins/netplugin.sock")
491492
vNode.RunCommand("sudo service docker restart")

test/systemtests/node_test.go

+32
Original file line numberDiff line numberDiff line change
@@ -110,6 +110,38 @@ func (n *node) cleanupMaster() {
110110
n.exec.cleanupMaster()
111111
}
112112

113+
func (n *node) verifyUplinkState(uplinks []string) error {
114+
var err error
115+
var portName string
116+
var cmd, output string
117+
118+
if len(uplinks) > 1 {
119+
portName = "uplinkPort"
120+
} else {
121+
portName = uplinks[0]
122+
}
123+
124+
// Verify port state
125+
cmd = fmt.Sprintf("sudo ovs-vsctl find Port name=%s", portName)
126+
output, err = n.runCommand(cmd)
127+
if err != nil || !(strings.Contains(string(output), portName)) {
128+
err = fmt.Errorf("Lookup failed for uplink Port %s. Err: %+v", portName, err)
129+
return err
130+
}
131+
132+
// Verify Interface state
133+
for _, uplink := range uplinks {
134+
cmd = fmt.Sprintf("sudo ovs-vsctl find Interface name=%s", uplink)
135+
output, err = n.runCommand(cmd)
136+
if err != nil || !(strings.Contains(string(output), uplink)) {
137+
err = fmt.Errorf("Lookup failed for uplink interface %s for uplink cfg:%+v. Err: %+v", uplink, uplinks, err)
138+
return err
139+
}
140+
}
141+
142+
return err
143+
}
144+
113145
func (n *node) runCommand(cmd string) (string, error) {
114146
var (
115147
str string

test/systemtests/swarm_test.go

+1
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ func (w *swarm) cleanupSlave() {
430430
vNode := w.node.tbnode
431431
vNode.RunCommand("sudo ovs-vsctl del-br contivVxlanBridge")
432432
vNode.RunCommand("sudo ovs-vsctl del-br contivVlanBridge")
433+
vNode.RunCommand("sudo ovs-vsctl del-br contivHostBridge")
433434
vNode.RunCommand("for p in `ifconfig | grep vport | awk '{print $1}'`; do sudo ip link delete $p type veth; done")
434435
}
435436

0 commit comments

Comments
 (0)