WIP - Suggesting changes (take2)
This is not yet completed, still working on things. Eventually the plan
is to provide the following changes
- restructure repo to be more aligned with https://github.com/golang-standards/project-layout
- add k8s probes
- modifications (golang range loops, etc) to follow some golang
practices
Change-Id: I6922cbc00b5ef17ceab183aba00a7fc59ab46480
diff --git a/internal/pkg/openflow/stats.go b/internal/pkg/openflow/stats.go
new file mode 100644
index 0000000..68d2625
--- /dev/null
+++ b/internal/pkg/openflow/stats.go
@@ -0,0 +1,619 @@
+/*
+ Copyright 2020 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/donNewtonAlpha/goloxi"
+ ofp "github.com/donNewtonAlpha/goloxi/of13"
+ "github.com/opencord/voltha-lib-go/v2/pkg/log"
+ "github.com/opencord/voltha-protos/v2/go/common"
+ "github.com/opencord/voltha-protos/v2/go/openflow_13"
+ "net"
+ "unsafe"
+)
+
+func (ofc *OFClient) handleStatsRequest(request ofp.IHeader, statType uint16) error {
+ if logger.V(log.DebugLevel) {
+ js, _ := json.Marshal(request)
+ logger.Debugw("handleStatsRequest called",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "stat-type": statType,
+ "request": js})
+ }
+
+ switch statType {
+ case ofp.OFPSTDesc:
+ statsReq := request.(*ofp.DescStatsRequest)
+ response, err := ofc.handleDescStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+ case ofp.OFPSTFlow:
+ statsReq := request.(*ofp.FlowStatsRequest)
+ response, err := ofc.handleFlowStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ response.Length = uint16(unsafe.Sizeof(*response))
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+
+ case ofp.OFPSTAggregate:
+ statsReq := request.(*ofp.AggregateStatsRequest)
+ response, err := ofc.handleAggregateStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+ case ofp.OFPSTTable:
+ statsReq := request.(*ofp.TableStatsRequest)
+ response, e := ofc.handleTableStatsRequest(statsReq)
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ if e != nil {
+ return e
+ }
+ return ofc.SendMessage(response)
+ case ofp.OFPSTPort:
+ statsReq := request.(*ofp.PortStatsRequest)
+ response, err := ofc.handlePortStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+ case ofp.OFPSTQueue:
+ statsReq := request.(*ofp.QueueStatsRequest)
+ response, err := ofc.handleQueueStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+ case ofp.OFPSTGroup:
+ statsReq := request.(*ofp.GroupStatsRequest)
+ response, err := ofc.handleGroupStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ ofc.SendMessage(response)
+ case ofp.OFPSTGroupDesc:
+ statsReq := request.(*ofp.GroupDescStatsRequest)
+ response, err := ofc.handleGroupStatsDescRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+
+ case ofp.OFPSTGroupFeatures:
+ statsReq := request.(*ofp.GroupFeaturesStatsRequest)
+ response, err := ofc.handleGroupFeatureStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+ case ofp.OFPSTMeter:
+ statsReq := request.(*ofp.MeterStatsRequest)
+ response, err := ofc.handleMeterStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+ case ofp.OFPSTMeterConfig:
+ statsReq := request.(*ofp.MeterConfigStatsRequest)
+ response, err := ofc.handleMeterConfigStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+ case ofp.OFPSTMeterFeatures:
+ statsReq := request.(*ofp.MeterFeaturesStatsRequest)
+ response, err := ofc.handleMeterFeatureStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+ case ofp.OFPSTTableFeatures:
+ statsReq := request.(*ofp.TableFeaturesStatsRequest)
+ response, err := ofc.handleTableFeaturesStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+ case ofp.OFPSTPortDesc:
+ statsReq := request.(*ofp.PortDescStatsRequest)
+ response, err := ofc.handlePortDescStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+
+ case ofp.OFPSTExperimenter:
+ statsReq := request.(*ofp.ExperimenterStatsRequest)
+ response, err := ofc.handleExperimenterStatsRequest(statsReq)
+ if err != nil {
+ return err
+ }
+ if logger.V(log.DebugLevel) {
+ reqJs, _ := json.Marshal(statsReq)
+ resJs, _ := json.Marshal(response)
+ logger.Debugw("handle-stats-request",
+ log.Fields{
+ "device-id": ofc.DeviceID,
+ "request": reqJs,
+ "response": resJs})
+ }
+ return ofc.SendMessage(response)
+ }
+ return nil
+}
+
+func (ofc *OFClient) handleDescStatsRequest(request *ofp.DescStatsRequest) (*ofp.DescStatsReply, error) {
+ response := ofp.NewDescStatsReply()
+ response.SetXid(request.GetXid())
+ response.SetVersion(request.GetVersion())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+
+ resp, err := ofc.VolthaClient.GetLogicalDevice(context.Background(),
+ &common.ID{Id: ofc.DeviceID})
+ 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))
+ return response, nil
+}
+
+func (ofc *OFClient) handleFlowStatsRequest(request *ofp.FlowStatsRequest) (*ofp.FlowStatsReply, error) {
+ response := ofp.NewFlowStatsReply()
+ response.SetXid(request.GetXid())
+ response.SetVersion(4)
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ resp, err := ofc.VolthaClient.ListLogicalDeviceFlows(context.Background(),
+ &common.ID{Id: ofc.DeviceID})
+ if err != nil {
+ return nil, err
+ }
+ var flow []*ofp.FlowStatsEntry
+ for _, item := range resp.GetItems() {
+ entry := ofp.NewFlowStatsEntry()
+ entry.SetTableId(uint8(item.GetTableId()))
+ 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())
+ entrySize := uint16(48)
+ match := ofp.NewMatchV3()
+ pbMatch := item.GetMatch()
+ match.SetType(uint16(pbMatch.GetType()))
+ size := uint16(4)
+ var fields []goloxi.IOxm
+ for _, oxmField := range pbMatch.GetOxmFields() {
+ field := oxmField.GetField()
+ ofbField := field.(*openflow_13.OfpOxmField_OfbField).OfbField
+ iOxm, oxmSize := parseOxm(ofbField, ofc.DeviceID)
+ fields = append(fields, iOxm)
+ if oxmSize > 0 {
+ size += 4 //header for oxm
+ }
+ size += oxmSize
+ }
+
+ match.OxmList = fields
+ match.Length = uint16(size)
+ //account for 8 byte alignment
+ if size%8 != 0 {
+ size = ((size / 8) + 1) * 8
+ }
+ entrySize += size
+ entry.SetMatch(*match)
+ var instructions []ofp.IInstruction
+ for _, ofpInstruction := range item.Instructions {
+ instruction, size := parseInstructions(ofpInstruction, ofc.DeviceID)
+ instructions = append(instructions, instruction)
+ entrySize += size
+ }
+ entry.Instructions = instructions
+ entry.Length = entrySize
+ entrySize = 0
+ flow = append(flow, entry)
+ }
+ response.SetEntries(flow)
+ return response, nil
+}
+
+func (ofc *OFClient) handleAggregateStatsRequest(request *ofp.AggregateStatsRequest) (*ofp.AggregateStatsReply, error) {
+ response := ofp.NewAggregateStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ response.SetFlowCount(0)
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+
+func (ofc *OFClient) handleGroupStatsRequest(request *ofp.GroupStatsRequest) (*ofp.GroupStatsReply, error) {
+ response := ofp.NewGroupStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ reply, err := ofc.VolthaClient.ListLogicalDeviceFlowGroups(context.Background(),
+ &common.ID{Id: ofc.DeviceID})
+ if err != nil {
+ return nil, err
+ }
+
+ var groupStatsEntries []*ofp.GroupStatsEntry
+ for _, item := range reply.GetItems() {
+ stats := item.GetStats()
+ var entry ofp.GroupStatsEntry
+ entry.SetByteCount(stats.GetByteCount())
+ entry.SetPacketCount(stats.GetPacketCount())
+ entry.SetDurationNsec(stats.GetDurationNsec())
+ entry.SetDurationSec(stats.GetDurationSec())
+ entry.SetRefCount(stats.GetRefCount())
+ entry.SetGroupId(stats.GetGroupId())
+ var bucketStatsList []*ofp.BucketCounter
+ for _, bucketStat := range stats.GetBucketStats() {
+ 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 (ofc *OFClient) handleGroupStatsDescRequest(request *ofp.GroupDescStatsRequest) (*ofp.GroupDescStatsReply, error) {
+ response := ofp.NewGroupDescStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ reply, err := ofc.VolthaClient.ListLogicalDeviceFlowGroups(context.Background(),
+ &common.ID{Id: ofc.DeviceID})
+ if err != nil {
+ return nil, err
+ }
+ var groupDescStatsEntries []*ofp.GroupDescStatsEntry
+ for _, item := range reply.GetItems() {
+ stats := item.GetStats()
+ var groupDesc ofp.GroupDescStatsEntry
+ groupDesc.SetGroupId(stats.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 (ofc *OFClient) handleGroupFeatureStatsRequest(request *ofp.GroupFeaturesStatsRequest) (*ofp.GroupFeaturesStatsReply, error) {
+ response := ofp.NewGroupFeaturesStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+
+func (ofc *OFClient) handleMeterStatsRequest(request *ofp.MeterStatsRequest) (*ofp.MeterStatsReply, error) {
+ response := ofp.NewMeterStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ resp, err := ofc.VolthaClient.ListLogicalDeviceMeters(context.Background(),
+ &common.ID{Id: ofc.DeviceID})
+ if err != nil {
+ return nil, err
+ }
+ size := uint16(40)
+ var meterStats []*ofp.MeterStats
+ for _, item := range resp.Items {
+ meterStat := ofp.NewMeterStats()
+ stats := item.Stats
+ meterStat.DurationNsec = stats.DurationNsec
+ meterStat.DurationSec = stats.DurationSec
+ meterStat.ByteInCount = stats.ByteInCount
+ meterStat.FlowCount = stats.FlowCount
+ meterStat.MeterId = stats.MeterId
+ var bandStats []*ofp.MeterBandStats
+ for _, bStat := range stats.BandStats {
+ bandStat := ofp.NewMeterBandStats()
+ bandStat.ByteBandCount = bStat.ByteBandCount
+ bandStat.PacketBandCount = bStat.PacketBandCount
+ bandStats = append(bandStats, bandStat)
+ size += 16
+ }
+ meterStat.SetBandStats(bandStats)
+ meterStat.Len = size
+ meterStats = append(meterStats, meterStat)
+ }
+ response.SetEntries(meterStats)
+ return response, nil
+}
+
+func (ofc *OFClient) handleMeterConfigStatsRequest(request *ofp.MeterConfigStatsRequest) (*ofp.MeterConfigStatsReply, error) {
+ response := ofp.NewMeterConfigStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+
+func (ofc *OFClient) handleTableFeaturesStatsRequest(request *ofp.TableFeaturesStatsRequest) (*ofp.TableFeaturesStatsReply, error) {
+ response := ofp.NewTableFeaturesStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+
+func (ofc *OFClient) handleTableStatsRequest(request *ofp.TableStatsRequest) (*ofp.TableStatsReply, error) {
+ var response = ofp.NewTableStatsReply()
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ return response, nil
+}
+
+func (ofc *OFClient) handleQueueStatsRequest(request *ofp.QueueStatsRequest) (*ofp.QueueStatsReply, error) {
+ response := ofp.NewQueueStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}
+
+func (ofc *OFClient) handlePortStatsRequest(request *ofp.PortStatsRequest) (*ofp.PortStatsReply, error) {
+ response := ofp.NewPortStatsReply()
+ response.SetXid(request.GetXid())
+ response.SetVersion(request.GetVersion())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ reply, err := ofc.VolthaClient.ListLogicalDevicePorts(context.Background(),
+ &common.ID{Id: ofc.DeviceID})
+ if err != nil {
+ return nil, err
+ }
+ var entries []*ofp.PortStatsEntry
+ if request.GetPortNo() == 0xffffffff { //all ports
+ for _, port := range reply.GetItems() {
+ entries = append(entries, parsePortStats(port))
+ }
+ } else { //find right port that is requested
+ for _, port := range reply.GetItems() {
+ if port.GetOfpPortStats().GetPortNo() == uint32(request.GetPortNo()) {
+ entries = append(entries, parsePortStats(port))
+ }
+ }
+ }
+ response.SetEntries(entries)
+ return response, nil
+}
+
+func (ofc *OFClient) handlePortDescStatsRequest(request *ofp.PortDescStatsRequest) (*ofp.PortDescStatsReply, error) {
+ response := ofp.NewPortDescStatsReply()
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ logicalDevice, err := ofc.VolthaClient.GetLogicalDevice(context.Background(),
+ &common.ID{Id: ofc.DeviceID})
+ if err != nil {
+ return nil, err
+ }
+ var entries []*ofp.PortDesc
+ for _, port := range logicalDevice.GetPorts() {
+ ofpPort := port.GetOfpPort()
+ var entry ofp.PortDesc
+ entry.SetPortNo(ofp.Port(ofpPort.GetPortNo()))
+
+ var octets []byte
+ for _, val := range ofpPort.GetHwAddr() {
+ octets = append(octets, byte(val))
+ }
+ hwAddr := net.HardwareAddr(octets)
+ entry.SetHwAddr(hwAddr)
+ entry.SetName(PadString(ofpPort.GetName(), 16))
+ entry.SetConfig(ofp.PortConfig(ofpPort.GetConfig()))
+ entry.SetState(ofp.PortState(ofpPort.GetState()))
+ entry.SetCurr(ofp.PortFeatures(ofpPort.GetCurr()))
+ entry.SetAdvertised(ofp.PortFeatures(ofpPort.GetAdvertised()))
+ entry.SetSupported(ofp.PortFeatures(ofpPort.GetSupported()))
+ entry.SetPeer(ofp.PortFeatures(ofpPort.GetPeer()))
+ entry.SetCurrSpeed(ofpPort.GetCurrSpeed())
+ entry.SetMaxSpeed(ofpPort.GetMaxSpeed())
+
+ entries = append(entries, &entry)
+ }
+
+ response.SetEntries(entries)
+ //TODO call voltha and get port descriptions etc
+ return response, nil
+
+}
+
+func (ofc *OFClient) handleMeterFeatureStatsRequest(request *ofp.MeterFeaturesStatsRequest) (*ofp.MeterFeaturesStatsReply, error) {
+ response := ofp.NewMeterFeaturesStatsReply()
+ response.SetXid(request.GetXid())
+ response.SetVersion(request.GetVersion())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ meterFeatures := ofp.NewMeterFeatures()
+ meterFeatures.Capabilities = ofp.OFPMFKbps
+ meterFeatures.BandTypes = ofp.OFPMBTDrop
+ meterFeatures.MaxMeter = 0xffffffff
+ meterFeatures.MaxBands = 0xff
+ meterFeatures.MaxColor = 0xff
+ response.Features = *meterFeatures
+ return response, nil
+}
+
+func (ofc *OFClient) handleExperimenterStatsRequest(request *ofp.ExperimenterStatsRequest) (*ofp.ExperimenterStatsReply, error) {
+ response := ofp.NewExperimenterStatsReply(request.GetExperimenter())
+ response.SetVersion(request.GetVersion())
+ response.SetXid(request.GetXid())
+ response.SetFlags(ofp.StatsReplyFlags(request.GetFlags()))
+ //TODO wire this to voltha core when it implements
+ return response, nil
+}