initial add - go fmt on grpc
Change-Id: Ib0afadd2fe5571d1456a091f94f5644458f7d3f4
diff --git a/openflow/barrier.go b/openflow/barrier.go
new file mode 100644
index 0000000..7b631fe
--- /dev/null
+++ b/openflow/barrier.go
@@ -0,0 +1,31 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "encoding/json"
+ ofp "github.com/skydive-project/goloxi/of13"
+ "log"
+)
+
+func handleBarrierRequest(request *ofp.BarrierRequest, client *Client) {
+ jsonRequest, _ := json.Marshal(request)
+ log.Printf("handleBarrierRequest called with %s", jsonRequest)
+ reply := ofp.NewBarrierReply()
+ reply.SetXid(request.GetXid())
+ client.SendMessage(reply)
+}
diff --git a/openflow/echo.go b/openflow/echo.go
new file mode 100644
index 0000000..51d09df
--- /dev/null
+++ b/openflow/echo.go
@@ -0,0 +1,33 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "encoding/json"
+ ofp "github.com/skydive-project/goloxi/of13"
+ "log"
+)
+
+func handleEchoRequest(request *ofp.EchoRequest, client *Client) {
+ jsonMessage, _ := json.Marshal(request)
+ log.Printf("handleEchoRequest called with %s", jsonMessage)
+ reply := ofp.NewEchoReply()
+ reply.SetXid(request.GetXid())
+ reply.SetVersion(request.GetVersion())
+ client.SendMessage(reply)
+
+}
diff --git a/openflow/feature.go b/openflow/feature.go
new file mode 100644
index 0000000..2c01f73
--- /dev/null
+++ b/openflow/feature.go
@@ -0,0 +1,50 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "context"
+ "encoding/json"
+ "github.com/opencord/voltha-protos/go/common"
+ pb "github.com/opencord/voltha-protos/go/voltha"
+ ofp "github.com/skydive-project/goloxi/of13"
+ "log"
+)
+
+func handleFeatureRequest(request *ofp.FeaturesRequest, deviceId string, client *Client) error {
+ message, _ := json.Marshal(request)
+ log.Printf("handleFeatureRequest called with %s\n ", message)
+ var grpcClient = *getGrpcClient()
+ var id = common.ID{Id: deviceId}
+ logicalDevice, err := grpcClient.GetLogicalDevice(context.Background(), &id)
+ reply := createFeaturesRequestReply(request.GetXid(), logicalDevice)
+ err = client.SendMessage(reply)
+ return err
+}
+func createFeaturesRequestReply(xid uint32, device *pb.LogicalDevice) *ofp.FeaturesReply {
+
+ featureReply := ofp.NewFeaturesReply()
+ featureReply.SetXid(xid)
+ features := device.GetSwitchFeatures()
+ featureReply.SetDatapathId(device.GetDatapathId())
+ featureReply.SetNBuffers(features.GetNBuffers())
+ featureReply.SetNTables(uint8(features.GetNTables()))
+ featureReply.SetAuxiliaryId(uint8(features.GetAuxiliaryId()))
+ capabilities := features.GetCapabilities()
+ featureReply.SetCapabilities(ofp.Capabilities(capabilities))
+ return featureReply
+}
diff --git a/openflow/flowMod.go b/openflow/flowMod.go
new file mode 100644
index 0000000..37e6864
--- /dev/null
+++ b/openflow/flowMod.go
@@ -0,0 +1,283 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "context"
+ "encoding/json"
+ "github.com/opencord/voltha-protos/go/openflow_13"
+ pb "github.com/opencord/voltha-protos/go/voltha"
+ ofp "github.com/skydive-project/goloxi/of13"
+ "log"
+)
+
+var oxmMap = map[string]int32{
+ "in_port": 0,
+ "in_phy_port": 1,
+ "metadata": 2,
+ "eth_dst": 3,
+ "eth_src": 4,
+ "eth_type": 5,
+ "vlan_vid": 6,
+ "vlan_pcp": 7,
+ "ip_dscp": 8,
+ "ip_ecn": 9,
+ "ip_proto": 10,
+ "ipv4_src": 11,
+ "ipv4_dst": 12,
+ "tcp_src": 13,
+ "tcp_dst": 14,
+ "udp_src": 15,
+ "udp_dst": 16,
+ "sctp_src": 17,
+ "sctp_dst": 18,
+ "icmpv4_type": 19,
+ "icmpv4_code": 20,
+ "arp_op": 21,
+ "arp_spa": 22,
+ "arp_tpa": 23,
+ "arp_sha": 24,
+ "arp_tha": 25,
+ "ipv6_src": 26,
+ "ipv6_dst": 27,
+ "ipv6_flabel": 28,
+ "icmpv6_type": 29,
+ "icmpv6_code": 30,
+ "ipv6_nd_target": 31,
+ "ipv6_nd_sll": 32,
+ "ipv6_nd_tll": 33,
+ "mpls_label": 34,
+ "mpls_tc": 35,
+ "mpls_bos": 36,
+ "pbb_isid": 37,
+ "tunnel_id": 38,
+ "ipv6_exthdr": 39,
+}
+
+func handleFlowAdd(flowAdd *ofp.FlowAdd, deviceId string) {
+ js, _ := json.Marshal(flowAdd)
+ log.Printf("handleFlowAdd called with %s", js)
+
+ var flowUpdate openflow_13.FlowTableUpdate
+ flowUpdate.Id = deviceId
+ var flowMod pb.OfpFlowMod
+ flowMod.Cookie = flowAdd.Cookie
+ flowMod.CookieMask = flowAdd.CookieMask
+ flowMod.TableId = uint32(flowAdd.TableId)
+ flowMod.Command = pb.OfpFlowModCommand_OFPFC_ADD
+ flowMod.IdleTimeout = uint32(flowAdd.IdleTimeout)
+ flowMod.HardTimeout = uint32(flowAdd.HardTimeout)
+ flowMod.Priority = uint32(flowAdd.Priority)
+ flowMod.BufferId = flowAdd.BufferId
+ flowMod.OutPort = uint32(flowAdd.OutPort)
+ flowMod.OutGroup = uint32(flowAdd.OutGroup)
+ flowMod.Flags = uint32(flowAdd.Flags)
+ inMatch := flowAdd.Match
+ var flowMatch pb.OfpMatch
+ flowMatch.Type = pb.OfpMatchType(inMatch.GetType())
+ var oxmList []*pb.OfpOxmField
+ inOxmList := inMatch.GetOxmList()
+ for i := 0; i < len(inOxmList); i++ {
+ oxmField := inOxmList[i]
+ j, _ := json.Marshal(oxmField)
+
+ name := oxmMap[oxmField.GetOXMName()]
+ log.Printf("\n\n\n %s %d %s\n\n\n", j, name, oxmField.GetOXMName())
+
+ val := oxmField.GetOXMValue()
+ var ofpOxmField pb.OfpOxmField
+ ofpOxmField.OxmClass = ofp.OFPXMCOpenflowBasic
+ var field pb.OfpOxmOfbField
+
+ field.Type = pb.OxmOfbFieldTypes(name)
+ log.Println("****\nFieldType: " + openflow_13.OxmOfbFieldTypes_name[name] + "\n\n\n\n")
+
+ var x openflow_13.OfpOxmField_OfbField
+ x.OfbField = &field
+ ofpOxmField.Field = &x
+
+ switch pb.OxmOfbFieldTypes(name) {
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
+ port := val.(ofp.Port)
+ var value pb.OfpOxmOfbField_Port
+ value.Port = uint32(port)
+ field.Value = &value
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
+ phyPort := val.(uint32)
+ var value pb.OfpOxmOfbField_PhysicalPort
+ value.PhysicalPort = phyPort
+ field.Value = &value
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_METADATA:
+ metadata := val.(uint64)
+ var value pb.OfpOxmOfbField_TableMetadata
+ value.TableMetadata = metadata
+ field.Value = &value
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_ETH_TYPE:
+ ethType := val.(ofp.EthernetType)
+ var value pb.OfpOxmOfbField_EthType
+ value.EthType = uint32(ethType)
+ field.Value = &value
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
+ proto := val.(ofp.IpPrototype)
+ var value pb.OfpOxmOfbField_IpProto
+ value.IpProto = uint32(proto)
+ field.Value = &value
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
+ udpSrc := val.(uint16)
+ var value pb.OfpOxmOfbField_UdpSrc
+ value.UdpSrc = uint32(udpSrc)
+ log.Printf("udpSrc %v", udpSrc)
+ field.Value = &value
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
+ udpDst := val.(uint16)
+ var value pb.OfpOxmOfbField_UdpDst
+ value.UdpDst = uint32(udpDst)
+ field.Value = &value
+ }
+ oxmList = append(oxmList, &ofpOxmField)
+ }
+ flowMatch.OxmFields = oxmList
+ flowMod.Match = &flowMatch
+ var instructions []*pb.OfpInstruction
+ ofpInstructions := flowAdd.GetInstructions()
+ for i := 0; i < len(ofpInstructions); i++ {
+ var instruction pb.OfpInstruction
+ ofpInstruction := ofpInstructions[i]
+ instructionType := ofpInstruction.GetType()
+ instruction.Type = uint32(instructionType)
+ switch instructionType {
+ case 1:
+ goToTable := ofpInstruction.(ofp.IInstructionGotoTable)
+ var ofpGoToTable openflow_13.OfpInstruction_GotoTable
+ ofpGoToTable.GotoTable.TableId = uint32(goToTable.GetTableId())
+ instruction.Data = &ofpGoToTable
+ case 2:
+ writeMetaData := ofpInstruction.(ofp.IInstructionWriteMetadata)
+ var ofpWriteMetadata openflow_13.OfpInstruction_WriteMetadata
+ ofpWriteMetadata.WriteMetadata.Metadata = writeMetaData.GetMetadata()
+ ofpWriteMetadata.WriteMetadata.MetadataMask = writeMetaData.GetMetadataMask()
+ instruction.Data = &ofpWriteMetadata
+ case 3:
+ writeAction := ofpInstruction.(ofp.IInstructionWriteActions)
+ var ofpInstructionActions openflow_13.OfpInstruction_Actions
+ var ofpActions []*openflow_13.OfpAction
+ actions := writeAction.GetActions()
+ for i := 0; i < len(actions); i++ {
+ action := actions[i]
+ ofpAction := extractAction(action)
+ ofpActions = append(ofpActions, ofpAction)
+ }
+ instruction.Data = &ofpInstructionActions
+ case 4:
+ applyAction := ofpInstruction.(ofp.IInstructionApplyActions)
+ var ofpInstructionActions openflow_13.OfpInstruction_Actions
+ var ofpActions []*openflow_13.OfpAction
+ actions := applyAction.GetActions()
+ for i := 0; i < len(actions); i++ {
+ action := actions[i]
+ ofpAction := extractAction(action)
+ ofpActions = append(ofpActions, ofpAction)
+ }
+ var actionsHolder openflow_13.OfpInstructionActions
+ actionsHolder.Actions = ofpActions
+ ofpInstructionActions.Actions = &actionsHolder
+ instruction.Data = &ofpInstructionActions
+
+ }
+ instructions = append(instructions, &instruction)
+ }
+
+ flowMod.Instructions = instructions
+ flowUpdate.FlowMod = &flowMod
+ grpcClient := *getGrpcClient()
+ flowUpdateJs, _ := json.Marshal(flowUpdate)
+ log.Printf("FLOW UPDATE %s", flowUpdateJs)
+ empty, err := grpcClient.UpdateLogicalDeviceFlowTable(context.Background(), &flowUpdate)
+ if err != nil {
+ log.Printf("ERROR DOING FLOW MOD ADD %v", err)
+ }
+ emptyJs, _ := json.Marshal(empty)
+ log.Printf("FLOW MOD RESPONSE %s", emptyJs)
+
+}
+
+func handleFlowMod(flowMod *ofp.FlowMod, deviceId string) {
+ js, _ := json.Marshal(flowMod)
+ log.Printf("handleFlowMod called with %s", js)
+}
+
+func handleFlowModStrict(flowModStrict *ofp.FlowModifyStrict, deviceId string) {
+ js, _ := json.Marshal(flowModStrict)
+ log.Printf("handleFlowModStrict called with %s", js)
+}
+func handleFlowDelete(flowDelete *ofp.FlowDelete, deviceId string) {
+ js, _ := json.Marshal(flowDelete)
+ log.Printf("handleFlowDelete called with %s", js)
+
+}
+func handleFlowDeleteStrict(flowDeleteStrict *ofp.FlowDeleteStrict, deviceId string) {
+ js, _ := json.Marshal(flowDeleteStrict)
+ log.Printf("handleFlowDeleteStrict called with %s", js)
+
+}
+func extractAction(action ofp.IAction) *openflow_13.OfpAction {
+ var ofpAction openflow_13.OfpAction
+ switch action.GetType() {
+ case 0: // Output
+ var outputAction openflow_13.OfpAction_Output
+ loxiOutputAction := action.(*ofp.ActionOutput)
+ var output openflow_13.OfpActionOutput
+ output.Port = uint32(loxiOutputAction.Port)
+ output.MaxLen = uint32(loxiOutputAction.MaxLen)
+ outputAction.Output = &output
+ ofpAction.Action = &outputAction
+ case 11: //CopyTtlOut
+ case 12: //CopyTtlIn
+ case 15: //SetMplsTtl
+ case 16: //DecMplsTtl
+ case 17: //PushVlan
+ var pushVlan openflow_13.OfpAction_Push
+ loxiPushAction := action.(*ofp.ActionPopVlan)
+ fields := loxiPushAction.GetActionFields()
+ fieldsJS, _ := json.Marshal(fields)
+ log.Printf("\n\nPushVlan fields %s\n\n", fieldsJS)
+ pushVlan.Push.Ethertype = 0x8100 //TODO This should be available in the fields
+ ofpAction.Type = openflow_13.OfpActionType_OFPAT_PUSH_VLAN
+ case 18: //PopVlan
+ ofpAction.Type = openflow_13.OfpActionType_OFPAT_POP_VLAN
+ case 19: //PushMpls
+ case 20: //PopMpls
+ case 21: //SetQueue
+ case 22: //ActionGroup
+ case 23: //SetNwTtl
+ case 24: //DecNwTtl
+ case 25: //SetField
+ var setField openflow_13.OfpAction_SetField
+ loxiSetField := action.(*ofp.ActionSetField)
+ fields := loxiSetField.GetActionFields()
+ fieldsJS, _ := json.Marshal(fields)
+ log.Printf("\n\nSet Fields fields %s\n\n", fieldsJS)
+
+ ofpAction.Action = &setField
+ case 26: //PushPbb
+ case 27: //PopPbb
+ case 65535: //Experimenter
+
+ }
+ return &ofpAction
+
+}
diff --git a/openflow/getConfig.go b/openflow/getConfig.go
new file mode 100644
index 0000000..6d4444f
--- /dev/null
+++ b/openflow/getConfig.go
@@ -0,0 +1,32 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "encoding/json"
+ ofp "github.com/skydive-project/goloxi/of13"
+ "log"
+)
+
+func handleGetConfigRequest(request *ofp.GetConfigRequest, client *Client) {
+ jsonReq, _ := json.Marshal(request)
+ log.Printf("handleGetConfigRequest called with %s", jsonReq)
+ reply := ofp.NewGetConfigReply()
+ reply.SetXid(request.GetXid())
+ reply.SetMissSendLen(ofp.OFPCMLNoBuffer)
+ client.SendMessage(reply)
+}
diff --git a/openflow/ofError.go b/openflow/ofError.go
new file mode 100644
index 0000000..c4329e1
--- /dev/null
+++ b/openflow/ofError.go
@@ -0,0 +1,29 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "encoding/json"
+ ofp "github.com/skydive-project/goloxi/of13"
+ "log"
+)
+
+func handleErrMsg(message *ofp.ErrorMsg) {
+ jsonMessage, _ := json.Marshal(message)
+ log.Printf("handleErrMsg called with %s", jsonMessage)
+ //Not sure yet what if anything to do here
+}
diff --git a/openflow/openflowClient.go b/openflow/openflowClient.go
new file mode 100644
index 0000000..b07e36d
--- /dev/null
+++ b/openflow/openflowClient.go
@@ -0,0 +1,258 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "encoding/json"
+ "fmt"
+ "time"
+
+ pb "github.com/opencord/voltha-protos/go/voltha"
+ "github.com/skydive-project/goloxi"
+ ofp "github.com/skydive-project/goloxi/of13"
+
+ "log"
+ "net"
+)
+
+var conn net.Conn
+var volthaClient *pb.VolthaServiceClient
+var packetOutChannel chan pb.PacketOut
+
+type Client struct {
+ OfServerAddress string
+ Port uint16
+ DeviceId string
+ KeepRunning bool
+}
+
+func NewClient(ofServerAddress string, port uint16, deviceId string, keepRunning bool) *Client {
+ client := Client{OfServerAddress: ofServerAddress, Port: port, DeviceId: deviceId, KeepRunning: keepRunning}
+ go client.Start()
+ return &client
+}
+
+func (client *Client) End() {
+ client.KeepRunning = false
+}
+func (client *Client) Start() {
+ addressLine := fmt.Sprintf("%s:%d", client.OfServerAddress, client.Port)
+ raddr, e := net.ResolveTCPAddr("tcp", addressLine)
+ if e != nil {
+ errMessage := fmt.Errorf("Unable to resolve %s", addressLine)
+ fmt.Println(errMessage)
+ }
+ for {
+ if client.KeepRunning {
+ connection, e := net.DialTCP("tcp", nil, raddr)
+ conn = connection
+ if e != nil {
+ log.Fatalf("unable to connect to %v", raddr)
+ }
+ defer conn.Close()
+ hello := ofp.NewHello()
+ hello.Xid = uint32(GetXid())
+ var elements []ofp.IHelloElem
+
+ elem := ofp.NewHelloElemVersionbitmap()
+ elem.SetType(ofp.OFPHETVersionbitmap)
+ elem.SetLength(8)
+ var bitmap = ofp.Uint32{Value: 16}
+ bitmaps := []*ofp.Uint32{&bitmap}
+
+ elem.SetBitmaps(bitmaps)
+
+ elements = append(elements, elem)
+
+ hello.SetElements(elements)
+ e = client.SendMessage(hello)
+ if e != nil {
+ log.Fatal(e)
+ }
+ for {
+ buf := make([]byte, 1500)
+ read, e := conn.Read(buf)
+ if e != nil {
+ log.Printf("Connection has died %v", e)
+ break
+ }
+ decoder := goloxi.NewDecoder(buf)
+ log.Printf("decoder offset %d baseOffset %d", decoder.Offset(), decoder.BaseOffset())
+ header, e := ofp.DecodeHeader(decoder)
+ log.Printf("received packet read: %d", read)
+
+ if e != nil {
+ log.Printf("decodeheader threw error %v", e)
+ }
+ message, _ := json.Marshal(header)
+ log.Printf("message %s\n", message)
+ client.parseHeader(header, buf) //first one is ready
+ len := header.GetLength()
+ if len < uint16(read) {
+ log.Printf("Len %d was less than read %d", len, read)
+ for {
+ read = read - int(len)
+ newBuf := buf[len:]
+ decoder = goloxi.NewDecoder(newBuf)
+ newHeader, e := ofp.DecodeHeader(decoder)
+ message, _ := json.Marshal(newHeader)
+ log.Printf("message %s\n", message)
+ if e != nil {
+
+ }
+ len = newHeader.GetLength()
+ client.parseHeader(newHeader, newBuf)
+ if read == int(len) {
+ log.Printf(" not continuing read %d len %d", read, len)
+ break
+ } else {
+ log.Printf("continuing read %d len %d", read, len)
+ }
+ buf = newBuf
+ }
+ }
+ if e != nil {
+ log.Println("Decode Header error ", e)
+ }
+ }
+ }
+ break
+ }
+}
+
+func (client *Client) parseHeader(header ofp.IHeader, buf []byte) {
+
+ log.Printf("parseHeader called with type %d", header.GetType())
+ switch header.GetType() {
+ case 0:
+ x := header.(*ofp.Hello)
+ log.Printf("helloMessage : %+v", x)
+ //nothing real to do
+ case 1:
+ errMsg := header.(*ofp.ErrorMsg)
+ go handleErrMsg(errMsg)
+ case 2:
+ echoReq := header.(*ofp.EchoRequest)
+ go handleEchoRequest(echoReq, client)
+ case 3:
+ //EchoReply
+ case 4:
+ //Expirementer
+ case 5:
+ featReq := header.(*ofp.FeaturesRequest)
+ go handleFeatureRequest(featReq, client.DeviceId, client)
+ case 6:
+ //feature reply
+ case 7:
+ configReq := header.(*ofp.GetConfigRequest)
+ go handleGetConfigRequest(configReq, client)
+ case 8:
+ //GetConfigReply
+ case 9:
+ setConf := header.(*ofp.SetConfig)
+ go handleSetConfig(setConf)
+ case 10:
+ //packetIn := header.(*ofp.PacketIn)
+ //go handlePacketIn(packetIn)
+ case 11:
+ //FlowRemoved
+ case 12:
+ //portStatus
+ case 13:
+ packetOut := header.(*ofp.PacketOut)
+ go handlePacketOut(packetOut, client.DeviceId)
+ case 14:
+ flowModType := uint8(buf[25])
+ switch flowModType {
+ case 0:
+ flowAdd := header.(*ofp.FlowAdd)
+ go handleFlowAdd(flowAdd, client.DeviceId)
+ //return DecodeFlowAdd(_flowmod, decoder)
+ case 1:
+ flowMod := header.(*ofp.FlowMod)
+ go handleFlowMod(flowMod, client.DeviceId)
+ //return DecodeFlowModify(_flowmod, decoder)
+ case 2:
+ flowModStrict := header.(*ofp.FlowModifyStrict)
+ go handleFlowModStrict(flowModStrict, client.DeviceId)
+ //return DecodeFlowModifyStrict(_flowmod, decoder)
+ case 3:
+ flowDelete := header.(*ofp.FlowDelete)
+ go handleFlowDelete(flowDelete, client.DeviceId)
+ //return DecodeFlowDelete(_flowmod, decoder)
+ case 4:
+ flowDeleteStrict := header.(*ofp.FlowDeleteStrict)
+ go handleFlowDeleteStrict(flowDeleteStrict, client.DeviceId)
+ //return DecodeFlowDeleteStrict(_flowmod, decoder)
+ default:
+ //return nil, fmt.Errorf("Invalid type '%d' for 'FlowMod'", _flowmod.Command)
+
+ }
+ case 18:
+ var statType = uint16(buf[8])<<8 + uint16(buf[9])
+ log.Println("statsType", statType)
+ go handleStatsRequest(header, statType, client.DeviceId, client)
+ case 20:
+ barRequest := header.(*ofp.BarrierRequest)
+ go handleBarrierRequest(barRequest, client)
+ case 24:
+ roleReq := header.(*ofp.RoleRequest)
+ go handleRoleRequest(roleReq, client)
+
+ }
+}
+
+//openFlowMessage created to allow for a single SendMessage
+type OpenFlowMessage interface {
+ Serialize(encoder *goloxi.Encoder) error
+}
+
+func (client *Client) SendMessage(message OpenFlowMessage) error {
+ jsonMessage, _ := json.Marshal(message)
+ log.Printf("send message called %s\n", jsonMessage)
+ enc := goloxi.NewEncoder()
+ message.Serialize(enc)
+ jMessage, _ := json.Marshal(message)
+ log.Printf("message after serialize %s", jMessage)
+
+ for {
+ if conn == nil {
+ log.Println("CONN IS NIL")
+ time.Sleep(10 * time.Millisecond)
+ } else {
+ break
+ }
+ }
+ _, err := conn.Write(enc.Bytes())
+ if err != nil {
+ log.Printf("SendMessage had error %s", err)
+ return err
+ }
+ return nil
+}
+func SetGrpcClient(client *pb.VolthaServiceClient) {
+ volthaClient = client
+}
+func getGrpcClient() *pb.VolthaServiceClient {
+ return volthaClient
+}
+func test(hello ofp.IHello) {
+ fmt.Println("works")
+}
+func SetPacketOutChannel(pktOutChan chan pb.PacketOut) {
+ packetOutChannel = pktOutChan
+}
diff --git a/openflow/packet.go b/openflow/packet.go
new file mode 100644
index 0000000..2bd46cd
--- /dev/null
+++ b/openflow/packet.go
@@ -0,0 +1,46 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "encoding/json"
+ pb "github.com/opencord/voltha-protos/go/voltha"
+ ofp "github.com/skydive-project/goloxi/of13"
+ "log"
+)
+
+func handlePacketOut(packetOut *ofp.PacketOut, deviceId string) {
+ jsonMessage, _ := json.Marshal(packetOut)
+ log.Printf("handlePacketOut called with %s", jsonMessage)
+ pktOut := pb.OfpPacketOut{}
+ pktOut.BufferId = packetOut.GetBufferId()
+ pktOut.InPort = uint32(packetOut.GetInPort())
+ var actions []*pb.OfpAction
+ inActions := packetOut.GetActions()
+ for i := 0; i < len(inActions); i++ {
+ action := inActions[i]
+ var newAction = pb.OfpAction{}
+ newAction.Type = pb.OfpActionType(action.GetType())
+ actions = append(actions, &newAction)
+ }
+ pktOut.Actions = actions
+ pktOut.Data = packetOut.GetData()
+ pbPacketOut := pb.PacketOut{}
+ pbPacketOut.PacketOut = &pktOut
+ pbPacketOut.Id = deviceId
+ packetOutChannel <- pbPacketOut
+}
diff --git a/openflow/role.go b/openflow/role.go
new file mode 100644
index 0000000..08cf457
--- /dev/null
+++ b/openflow/role.go
@@ -0,0 +1,35 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "encoding/json"
+ ofp "github.com/skydive-project/goloxi/of13"
+ "log"
+)
+
+func handleRoleRequest(request *ofp.RoleRequest, client *Client) {
+ jsonMessage, _ := json.Marshal(request)
+ log.Printf("handleRoleRequest called with %s", jsonMessage)
+
+ reply := ofp.NewRoleReply()
+ reply.SetXid(request.GetXid())
+ reply.SetVersion(request.GetVersion())
+ reply.SetRole(request.GetRole())
+ reply.SetGenerationId(request.GetGenerationId())
+ client.SendMessage(reply)
+}
diff --git a/openflow/setConfig.go b/openflow/setConfig.go
new file mode 100644
index 0000000..c429f46
--- /dev/null
+++ b/openflow/setConfig.go
@@ -0,0 +1,28 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "encoding/json"
+ ofp "github.com/skydive-project/goloxi/of13"
+ "log"
+)
+
+func handleSetConfig(request *ofp.SetConfig) {
+ jsonMessage, _ := json.Marshal(request)
+ log.Printf("handleSetConfig %s\n", jsonMessage)
+}
diff --git a/openflow/stats.go b/openflow/stats.go
new file mode 100644
index 0000000..46fe2f2
--- /dev/null
+++ b/openflow/stats.go
@@ -0,0 +1,518 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "context"
+ "encoding/json"
+ "github.com/opencord/voltha-protos/go/openflow_13"
+ "github.com/skydive-project/goloxi"
+ "log"
+ "net"
+ "unsafe"
+
+ "github.com/opencord/voltha-protos/go/common"
+ pb "github.com/opencord/voltha-protos/go/voltha"
+ ofp "github.com/skydive-project/goloxi/of13"
+)
+
+func handleStatsRequest(request ofp.IHeader, statType uint16, deviceId string, client *Client) error {
+ message, _ := json.Marshal(request)
+ log.Printf("handleStatsRequest called with %s\n ", message)
+ var id = common.ID{Id: deviceId}
+
+ switch statType {
+ case 0:
+ statsReq := request.(*ofp.DescStatsRequest)
+ response, err := handleDescStatsRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+
+ case 1:
+ statsReq := request.(*ofp.FlowStatsRequest)
+ response, _ := handleFlowStatsRequest(statsReq, id)
+ err := client.SendMessage(response)
+ if err != nil {
+ return err
+ }
+
+ case 2:
+ statsReq := request.(*ofp.AggregateStatsRequest)
+ aggregateStatsReply, err := handleAggregateStatsRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(aggregateStatsReply)
+ case 3:
+ statsReq := request.(*ofp.TableStatsRequest)
+ tableStatsReply, e := handleTableStatsRequest(statsReq, id)
+ if e != nil {
+ return e
+ }
+ client.SendMessage(tableStatsReply)
+ case 4:
+ statsReq := request.(*ofp.PortStatsRequest)
+ response, err := handlePortStatsRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+
+ case 5:
+ statsReq := request.(*ofp.QueueStatsRequest)
+ response, err := handleQueueStatsRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+ case 6:
+ statsReq := request.(*ofp.GroupStatsRequest)
+ response, err := handleGroupStatsRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+ case 7:
+ statsReq := request.(*ofp.GroupDescStatsRequest)
+ response, err := handleGroupStatsDescRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+ case 8:
+ statsReq := request.(*ofp.GroupFeaturesStatsRequest)
+ response, err := handleGroupFeatureStatsRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+ case 9:
+ statsReq := request.(*ofp.MeterStatsRequest)
+ response, err := handleMeterStatsRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+ case 10:
+ statsReq := request.(*ofp.MeterConfigStatsRequest)
+ response, err := handleMeterConfigStatsRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+ case 11:
+ statsReq := request.(*ofp.MeterFeaturesStatsRequest)
+ response, err := handleMeterFeatureStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+ case 12:
+ statsReq := request.(*ofp.TableFeaturesStatsRequest)
+ response, err := handleTableFeaturesStatsRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+ case 13:
+ statsReq := request.(*ofp.PortDescStatsRequest)
+ response, err := handlePortDescStatsRequest(statsReq, deviceId)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+
+ case 65535:
+ statsReq := request.(*ofp.ExperimenterStatsRequest)
+ response, err := handleExperimenterStatsRequest(statsReq, id)
+ if err != nil {
+ return err
+ }
+ client.SendMessage(response)
+ }
+ return nil
+}
+
+func handleDescStatsRequest(request *ofp.DescStatsRequest, id common.ID) (*ofp.DescStatsReply, error) {
+ response := ofp.NewDescStatsReply()
+ response.SetXid(request.GetXid())
+ response.SetVersion(request.GetVersion())
+ client := *getGrpcClient()
+ resp, err := client.GetLogicalDevice(context.Background(), &id)
+ if err != nil {
+ return nil, err
+ }
+ desc := resp.GetDesc()
+
+ response.SetMfrDesc(PadString(desc.GetMfrDesc(), 256))
+ response.SetHwDesc(PadString(desc.GetHwDesc(), 256))
+ response.SetSwDesc(PadString(desc.GetSwDesc(), 256))
+ response.SetSerialNum(PadString(desc.GetSerialNum(), 32))
+ response.SetDpDesc(PadString(desc.GetDpDesc(), 256))
+ //jsonRes,_ := json.Marshal(response)
+ //log.Printf("handleDescStatsRequest response : %s",jsonRes)
+ return response, nil
+}
+func handleFlowStatsRequest(request *ofp.FlowStatsRequest, id common.ID) (*ofp.FlowStatsReply, error) {
+ log.Println("****************************************\n***********************************")
+ response := ofp.NewFlowStatsReply()
+ response.SetXid(request.GetXid())
+ response.SetVersion(request.GetVersion())
+ client := *getGrpcClient()
+ resp, err := client.ListLogicalDeviceFlows(context.Background(), &id)
+ if err != nil {
+ log.Println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
+ log.Printf("err in handleFlowStatsRequest calling ListLogicalDeviceFlows %v", err)
+ return nil, err
+ }
+ log.Println("++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++")
+ js, _ := json.Marshal(resp.GetItems())
+ log.Printf("||||||||||||||||||||||||||||||||||||HandFlowStat %s|||||||||||||||||||||||||||||||||||||||||", js)
+ var flow []*ofp.FlowStatsEntry
+ items := resp.GetItems()
+
+ for i := 0; i < len(items); i++ {
+ item := items[1]
+ var entry ofp.FlowStatsEntry
+
+ entry.SetTableId(uint8(item.GetId()))
+ entry.SetDurationSec(item.GetDurationSec())
+ entry.SetDurationNsec(item.GetDurationNsec())
+ entry.SetPriority(uint16(item.GetPriority()))
+ entry.SetIdleTimeout(uint16(item.GetIdleTimeout()))
+ entry.SetHardTimeout(uint16(item.GetHardTimeout()))
+ entry.SetFlags(ofp.FlowModFlags(item.GetFlags()))
+ entry.SetCookie(item.GetCookie())
+ entry.SetPacketCount(item.GetPacketCount())
+ entry.SetByteCount(item.GetByteCount())
+ var match ofp.Match
+ pbMatch := item.GetMatch()
+
+ var fields []goloxi.IOxm
+ match.SetType(uint16(pbMatch.GetType()))
+ oxFields := pbMatch.GetOxmFields()
+ for i := 0; i < len(oxFields); i++ {
+ js, _ := json.Marshal(oxFields[i])
+ log.Printf("oxfields %s", js)
+ oxmField := oxFields[i]
+ field := oxmField.GetField()
+ ofbField := field.(*openflow_13.OfpOxmField_OfbField).OfbField
+ switch ofbField.Type {
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_IN_PORT:
+ ofpInPort := ofp.NewOxmInPort()
+ val := ofbField.GetValue().(*openflow_13.OfpOxmOfbField_Port)
+ ofpInPort.Value = ofp.Port(val.Port)
+ fields = append(fields, ofpInPort)
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_IN_PHY_PORT:
+ ofpInPhyPort := ofp.NewOxmInPhyPort()
+ val := ofbField.GetValue().(*openflow_13.OfpOxmOfbField_PhysicalPort)
+ ofpInPhyPort.Value = ofp.Port(val.PhysicalPort)
+ fields = append(fields, ofpInPhyPort)
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_IP_PROTO:
+ ofpIpProto := ofp.NewOxmIpProto()
+ val := ofbField.GetValue().(*openflow_13.OfpOxmOfbField_IpProto)
+ ofpIpProto.Value = ofp.IpPrototype(val.IpProto)
+ fields = append(fields, ofpIpProto)
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_UDP_SRC:
+ ofpUdpSrc := ofp.NewOxmUdpSrc()
+ val := ofbField.GetValue().(*openflow_13.OfpOxmOfbField_UdpSrc)
+ ofpUdpSrc.Value = uint16(val.UdpSrc)
+ fields = append(fields, ofpUdpSrc)
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_UDP_DST:
+ ofpUdpDst := ofp.NewOxmUdpSrc()
+ val := ofbField.GetValue().(*openflow_13.OfpOxmOfbField_UdpDst)
+ ofpUdpDst.Value = uint16(val.UdpDst)
+ fields = append(fields, ofpUdpDst)
+ case pb.OxmOfbFieldTypes_OFPXMT_OFB_VLAN_VID:
+ ofpVlanVid := ofp.NewOxmVlanVid()
+ val := ofbField.GetValue().(*openflow_13.OfpOxmOfbField_VlanVid)
+ ofpVlanVid.Value = uint16(val.VlanVid)
+ fields = append(fields, ofpVlanVid)
+ default:
+ log.Printf("handleFlowStatsRequest Unhandled OxmField %v", ofbField.Type)
+ }
+
+ }
+ match.OxmList = fields
+ match.Length = uint16(unsafe.Sizeof(match))
+ entry.SetMatch(match)
+ var instructions []ofp.IInstruction
+ ofpInstructions := item.Instructions
+ for i := 0; i < len(ofpInstructions); i++ {
+ ofpInstruction := ofpInstructions[i]
+ instType := ofpInstruction.Type
+ switch instType {
+ case uint32(openflow_13.OfpInstructionType_OFPIT_APPLY_ACTIONS):
+ ofpActions := ofpInstruction.GetActions().Actions
+ for i := 0; i < len(ofpActions); i++ {
+ ofpAction := ofpActions[i]
+ var actions []*ofp.Action
+ switch ofpAction.Type {
+ case openflow_13.OfpActionType_OFPAT_OUTPUT:
+ ofpOutputAction := ofpAction.GetOutput()
+ outputAction := ofp.NewActionOutput()
+ outputAction.Port = ofp.Port(ofpOutputAction.Port)
+ outputAction.MaxLen = uint16(ofpOutputAction.MaxLen)
+ actions = append(actions, outputAction.Action)
+ }
+ }
+ instruction := ofp.NewInstruction(uint16(instType))
+ instructions = append(instructions, instruction)
+ }
+
+ }
+ entry.Instructions = instructions
+ entry.Length = uint16(unsafe.Sizeof(entry))
+ flow = append(flow, &entry)
+
+ }
+ response.SetEntries(flow)
+ return response, nil
+}
+func handleAggregateStatsRequest(request *ofp.AggregateStatsRequest, id common.ID) (*ofp.AggregateStatsReply, error) {
+ response := ofp.NewAggregateStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlowCount(0)
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+func handleGroupStatsRequest(request *ofp.GroupStatsRequest, id common.ID) (*ofp.GroupStatsReply, error) {
+ response := ofp.NewGroupStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ client := *getGrpcClient()
+ reply, err := client.ListLogicalDeviceFlowGroups(context.Background(), &id)
+ if err != nil {
+ return nil, err
+ }
+
+ var groupStatsEntries []*ofp.GroupStatsEntry
+ items := reply.GetItems()
+ for i := 0; i < len(items); i++ {
+ item := items[i].GetStats()
+ var entry ofp.GroupStatsEntry
+ entry.SetByteCount(item.GetByteCount())
+ entry.SetPacketCount(item.GetPacketCount())
+ entry.SetDurationNsec(item.GetDurationNsec())
+ entry.SetDurationSec(item.GetDurationSec())
+ entry.SetRefCount(item.GetRefCount())
+ entry.SetGroupId(item.GetGroupId())
+ bucketStats := item.GetBucketStats()
+ var bucketStatsList []*ofp.BucketCounter
+ for j := 0; j < len(bucketStats); j++ {
+ bucketStat := bucketStats[i]
+ var bucketCounter ofp.BucketCounter
+ bucketCounter.SetPacketCount(bucketStat.GetPacketCount())
+ bucketCounter.SetByteCount(bucketStat.GetByteCount())
+ bucketStatsList = append(bucketStatsList, &bucketCounter)
+ }
+ entry.SetBucketStats(bucketStatsList)
+ groupStatsEntries = append(groupStatsEntries, &entry)
+ }
+ response.SetEntries(groupStatsEntries)
+ return response, nil
+}
+func handleGroupStatsDescRequest(request *ofp.GroupDescStatsRequest, id common.ID) (*ofp.GroupDescStatsReply, error) {
+ response := ofp.NewGroupDescStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ client := *getGrpcClient()
+ reply, err := client.ListLogicalDeviceFlowGroups(context.Background(), &id)
+ if err != nil {
+ return nil, err
+ }
+ entries := reply.GetItems()
+ var groupDescStatsEntries []*ofp.GroupDescStatsEntry
+ for i := 0; i < len(entries); i++ {
+ item := entries[i].GetStats()
+ var groupDesc ofp.GroupDescStatsEntry
+ groupDesc.SetGroupId(item.GetGroupId())
+ /*
+ buckets := item.g
+ var bucketList []*ofp.Bucket
+ for j:=0;j<len(buckets);j++{
+
+ }
+
+ groupDesc.SetBuckets(bucketList)
+ */
+ groupDescStatsEntries = append(groupDescStatsEntries, &groupDesc)
+ }
+ response.SetEntries(groupDescStatsEntries)
+ return response, nil
+}
+func handleGroupFeatureStatsRequest(request *ofp.GroupFeaturesStatsRequest, id common.ID) (*ofp.GroupFeaturesStatsReply, error) {
+ response := ofp.NewGroupFeaturesStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+func handleMeterStatsRequest(request *ofp.MeterStatsRequest, id common.ID) (*ofp.MeterStatsReply, error) {
+ response := ofp.NewMeterStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+
+//statsReq := request.(*ofp.MeterConfigStatsRequest)
+func handleMeterConfigStatsRequest(request *ofp.MeterConfigStatsRequest, id common.ID) (*ofp.MeterConfigStatsReply, error) {
+ response := ofp.NewMeterConfigStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+
+//statsReq := request.(*ofp.TableFeaturesStatsRequest)
+func handleTableFeaturesStatsRequest(request *ofp.TableFeaturesStatsRequest, id common.ID) (*ofp.TableFeaturesStatsReply, error) {
+ response := ofp.NewTableFeaturesStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+func handleTableStatsRequest(request *ofp.TableStatsRequest, id common.ID) (*ofp.TableStatsReply, error) {
+ var tableStatsReply = ofp.NewTableStatsReply()
+ tableStatsReply.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ tableStatsReply.SetVersion(request.GetVersion())
+ tableStatsReply.SetXid(request.GetXid())
+ return tableStatsReply, nil
+}
+func handleQueueStatsRequest(request *ofp.QueueStatsRequest, id common.ID) (*ofp.QueueStatsReply, error) {
+ response := ofp.NewQueueStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+func handlePortStatsRequest(request *ofp.PortStatsRequest, id common.ID) (*ofp.PortStatsReply, error) {
+ log.Println("HERE")
+ response := ofp.NewPortStatsReply()
+ response.SetXid(request.GetXid())
+ response.SetVersion(request.GetVersion())
+ //response.SetFlags(ofp.flagsrequest.GetFlags())
+ client := *getGrpcClient()
+ reply, err := client.ListLogicalDevicePorts(context.Background(), &id)
+ //reply,err := client.GetLogicalDevicePort(context.Background(),&id)
+ if err != nil {
+ log.Printf("error calling ListDevicePorts %v", err)
+ return nil, err
+ }
+ js, _ := json.Marshal(reply)
+ log.Printf("PORT STATS REPLY %s", js)
+ ports := reply.GetItems()
+ var entries []*ofp.PortStatsEntry
+ if request.GetPortNo() == 0xffffffff { //all ports
+ for i := 0; i < len(ports); i++ {
+ port := ports[i]
+ entry := parsePortStats(port)
+ entries = append(entries, &entry)
+ }
+ } else { //find right port that is requested
+ for i := 0; i < len(ports); i++ {
+ if ports[i].GetOfpPortStats().GetPortNo() == uint32(request.GetPortNo()) {
+ entry := parsePortStats(ports[i])
+ entries = append(entries, &entry)
+ }
+ }
+ }
+ response.SetEntries(entries)
+ js, _ = json.Marshal(response)
+ log.Printf("handlePortStatsResponse %s", js)
+ return response, nil
+
+}
+func parsePortStats(port *pb.LogicalPort) ofp.PortStatsEntry {
+ stats := port.OfpPortStats
+ var entry ofp.PortStatsEntry
+ entry.SetPortNo(ofp.Port(stats.GetPortNo()))
+ entry.SetRxPackets(stats.GetRxPackets())
+ entry.SetTxPackets(stats.GetTxPackets())
+ entry.SetRxBytes(stats.GetRxBytes())
+ entry.SetTxBytes(stats.GetTxBytes())
+ entry.SetRxDropped(stats.GetRxDropped())
+ entry.SetTxDropped(stats.GetTxDropped())
+ entry.SetRxErrors(stats.GetRxErrors())
+ entry.SetTxErrors(stats.GetTxErrors())
+ entry.SetRxFrameErr(stats.GetRxFrameErr())
+ entry.SetRxOverErr(stats.GetRxOverErr())
+ entry.SetRxCrcErr(stats.GetRxCrcErr())
+ entry.SetCollisions(stats.GetCollisions())
+ entry.SetDurationSec(stats.GetDurationSec())
+ entry.SetDurationNsec(stats.GetDurationNsec())
+ return entry
+}
+func handlePortDescStatsRequest(request *ofp.PortDescStatsRequest, deviceId string) (*ofp.PortDescStatsReply, error) {
+ response := ofp.NewPortDescStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ var grpcClient = *getGrpcClient()
+ var id = common.ID{Id: deviceId}
+ logicalDevice, err := grpcClient.GetLogicalDevice(context.Background(), &id)
+ if err != nil {
+ return nil, err
+ }
+ ports := logicalDevice.GetPorts()
+ var entries []*ofp.PortDesc
+ for i := 0; i < len(ports); i++ {
+ var entry ofp.PortDesc
+ port := ports[i].GetOfpPort()
+ entry.SetPortNo(ofp.Port(port.GetPortNo()))
+
+ intArray := port.GetHwAddr()
+ var octets []byte
+ for i := 0; i < len(intArray); i++ {
+ octets = append(octets, byte(intArray[i]))
+ }
+ hwAddr := net.HardwareAddr(octets)
+ entry.SetHwAddr(hwAddr)
+ entry.SetName(PadString(port.GetName(), 16))
+ entry.SetConfig(ofp.PortConfig(port.GetConfig()))
+ entry.SetState(ofp.PortState(port.GetState()))
+ entry.SetCurr(ofp.PortFeatures(port.GetCurr()))
+ entry.SetAdvertised(ofp.PortFeatures(port.GetAdvertised()))
+ entry.SetSupported(ofp.PortFeatures(port.GetSupported()))
+ entry.SetPeer(ofp.PortFeatures(port.GetPeer()))
+ entry.SetCurrSpeed(port.GetCurrSpeed())
+ entry.SetMaxSpeed(port.GetMaxSpeed())
+
+ entries = append(entries, &entry)
+ }
+
+ response.SetEntries(entries)
+ //TODO call voltha and get port descriptions etc
+ return response, nil
+
+}
+func handleMeterFeatureStatsRequest(request *ofp.MeterFeaturesStatsRequest) (*ofp.MeterFeaturesStatsReply, error) {
+ response := ofp.NewMeterFeaturesStatsReply()
+ response.SetXid(request.GetXid())
+ response.SetVersion(request.GetVersion())
+ return response, nil
+}
+func handleExperimenterStatsRequest(request *ofp.ExperimenterStatsRequest, id common.ID) (*ofp.ExperimenterStatsReply, error) {
+ response := ofp.NewExperimenterStatsReply(request.GetExperimenter())
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
diff --git a/openflow/utils.go b/openflow/utils.go
new file mode 100644
index 0000000..160b2ab
--- /dev/null
+++ b/openflow/utils.go
@@ -0,0 +1,40 @@
+/*
+ Copyright 2017 the original author or authors.
+
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
+
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
+*/
+
+package openflow
+
+import (
+ "fmt"
+ "strings"
+ "sync"
+)
+
+var mu sync.Mutex
+var xid uint32 = 1
+
+func GetXid() uint32 {
+ mu.Lock()
+ defer mu.Unlock()
+ xid++
+ return xid
+}
+func PadString(value string, padSize int) string {
+ size := len(value)
+ nullsNeeded := padSize - size
+ null := fmt.Sprintf("%c", '\000')
+ padded := strings.Repeat(null, nullsNeeded)
+ return fmt.Sprintf("%s%s", value, padded)
+}