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)
+}