From 3796388862c923eda4b961efae423624c54a946b Mon Sep 17 00:00:00 2001 From: Wenying Dong Date: Tue, 8 Oct 2024 10:23:31 -0700 Subject: [PATCH] Add support for PortStatus message. (#82) Add function PortStatusRcvd in AppInterface to notify the applications when a PortStatus message is received from the OpenFlow switch. Signed-off-by: Wenying Dong --- VERSION | 2 +- ofctrl/ofSwitch.go | 3 +- ofctrl/ofctrl.go | 3 ++ ofctrl/ofctrl_test.go | 83 +++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 89 insertions(+), 2 deletions(-) diff --git a/VERSION b/VERSION index 6345c216..4a29f93b 100644 --- a/VERSION +++ b/VERSION @@ -1 +1 @@ -v0.13.0 +v0.14.0 diff --git a/ofctrl/ofSwitch.go b/ofctrl/ofSwitch.go index a458232a..c2056cfd 100755 --- a/ofctrl/ofSwitch.go +++ b/ofctrl/ofSwitch.go @@ -325,7 +325,8 @@ func (self *OFSwitch) handleMessages(dpid net.HardwareAddr, msg util.Message) { case *openflow15.FlowRemoved: case *openflow15.PortStatus: - // FIXME: This needs to propagated to the app. + // Propagate the PortStatus message to the app. + self.app.PortStatusRcvd(t) case *openflow15.PacketOut: case *openflow15.FlowMod: diff --git a/ofctrl/ofctrl.go b/ofctrl/ofctrl.go index f53504ee..09bba958 100644 --- a/ofctrl/ofctrl.go +++ b/ofctrl/ofctrl.go @@ -100,6 +100,9 @@ type AppInterface interface { FlowGraphEnabledOnSwitch() bool TLVMapEnabledOnSwitch() bool + + // PortStatusRcvd notifies AppInterface a new PortStatus message is received. + PortStatusRcvd(status *openflow15.PortStatus) } type ConnectionRetryControl interface { diff --git a/ofctrl/ofctrl_test.go b/ofctrl/ofctrl_test.go index e0c5fe07..1440fbf6 100644 --- a/ofctrl/ofctrl_test.go +++ b/ofctrl/ofctrl_test.go @@ -15,6 +15,7 @@ limitations under the License. package ofctrl import ( + "bytes" "encoding/binary" "fmt" "net" @@ -41,6 +42,8 @@ type OfActor struct { pktInCount int tlvTableStatus *TLVTableStatus tlvMapCh chan struct{} + + portStatusCh chan *openflow15.PortStatus } func (o *OfActor) PacketRcvd(sw *OFSwitch, packet *PacketIn) { @@ -81,6 +84,12 @@ func (o *OfActor) TLVMapEnabledOnSwitch() bool { return true } +func (o *OfActor) PortStatusRcvd(status *openflow15.PortStatus) { + if o.portStatusCh != nil { + o.portStatusCh <- status + } +} + // Controller/Application/ovsBr work on clientMode var ofActor *OfActor var ctrler *Controller @@ -2387,3 +2396,77 @@ func TestWriteactionsFlows(t *testing.T) { "conjunction(101,2/3)") } + +func TestPortStatusRcvd(t *testing.T) { + app := new(OfActor) + ctrl := NewController(app) + brName := "br4PortStatus" + ovsBr := prepareControllerAndSwitch(t, app, ctrl, brName) + defer func() { + assert.Nilf(t, ovsBr.DeleteBridge(brName), "Failed to delete br %s", brName) + ctrl.Delete() + }() + + portStatusCh := make(chan *openflow15.PortStatus) + app.portStatusCh = portStatusCh + + for _, tc := range []struct { + name string + portName string + portNo int + requestOFPort bool + }{ + { + name: "OVS port without ofport_request", + portName: "p1", + portNo: 1, + requestOFPort: false, + }, { + name: "OVS port with ofport_request", + portName: "p2", + portNo: 100, + requestOFPort: true, + }, + } { + t.Run(tc.name, func(t *testing.T) { + // OVSDB operation to add port. + cmd := fmt.Sprintf("ovs-vsctl --may-exist add-port %s %s -- set Interface %s type=internal", brName, tc.portName, tc.portName) + if tc.requestOFPort { + cmd = fmt.Sprintf("%s ofport_request=%d", cmd, tc.portNo) + } + err := exec.Command("/bin/bash", "-c", cmd).Run() + require.NoError(t, err) + + // Verifications on the PortStatus message -- Add. + addPort := <-portStatusCh + assert.Equal(t, openflow15.PR_ADD, int(addPort.Reason)) + assert.Equal(t, openflow15.PS_LINK_DOWN, int(addPort.Desc.State)) + assert.Equal(t, tc.portName, string(bytes.Trim(addPort.Desc.Name, "\x00"))) + assert.Equal(t, tc.portNo, int(addPort.Desc.PortNo)) + + // Set ip link up. + cmd = fmt.Sprintf("ip link set %s up", tc.portName) + err = exec.Command("/bin/bash", "-c", cmd).Run() + require.NoError(t, err) + + // Verifications on the PortStatus message -- Modify. + modPort := <-portStatusCh + assert.Equal(t, openflow15.PR_MODIFY, int(modPort.Reason)) + assert.Equal(t, openflow15.PS_LIVE, int(modPort.Desc.State)) + assert.Equal(t, tc.portName, string(bytes.Trim(modPort.Desc.Name, "\x00"))) + assert.Equal(t, tc.portNo, int(modPort.Desc.PortNo)) + + // OVSDB operation to delete port. + cmd = fmt.Sprintf("ovs-vsctl del-port %s %s", brName, tc.portName) + err = exec.Command("/bin/bash", "-c", cmd).Run() + require.NoError(t, err) + + // Verifications on the PortStatus message -- Delete. + delPort := <-portStatusCh + assert.Equal(t, openflow15.PR_DELETE, int(delPort.Reason)) + assert.Equal(t, openflow15.PS_LIVE, int(delPort.Desc.State)) + assert.Equal(t, tc.portName, string(bytes.Trim(delPort.Desc.Name, "\x00"))) + assert.Equal(t, tc.portNo, int(delPort.Desc.PortNo)) + }) + } +}