Tibit: Disabling auto KPI collection for now.
Change-Id: Icef8131eed5cf149d4f27e3e813f97d71a93d5e7
diff --git a/voltha/adapters/dpoe_onu/__init__.py b/voltha/adapters/dpoe_onu/__init__.py
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/voltha/adapters/dpoe_onu/__init__.py
diff --git a/voltha/adapters/dpoe_onu/dpoe_onu.py b/voltha/adapters/dpoe_onu/dpoe_onu.py
new file mode 100644
index 0000000..e1877e9
--- /dev/null
+++ b/voltha/adapters/dpoe_onu/dpoe_onu.py
@@ -0,0 +1,435 @@
+#
+# 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.
+#
+
+"""
+DPoE ONU device adapter
+"""
+
+import json
+
+from uuid import uuid4
+
+import structlog
+from zope.interface import implementer
+
+from binascii import hexlify
+
+from scapy.layers.inet import ICMP, IP
+from scapy.layers.l2 import Ether, Dot1Q
+from twisted.internet.defer import DeferredQueue, inlineCallbacks
+from twisted.internet import reactor
+
+from voltha.core.flow_decomposer import *
+from voltha.core.logical_device_agent import mac_str_to_tuple
+
+from voltha.adapters.interface import IAdapterInterface
+from voltha.protos.adapter_pb2 import Adapter, AdapterConfig
+from voltha.protos.device_pb2 import Port
+from voltha.protos.device_pb2 import DeviceType, DeviceTypes
+from voltha.protos.health_pb2 import HealthStatus
+from voltha.protos.common_pb2 import LogLevel, ConnectStatus
+from voltha.protos.common_pb2 import OperStatus, AdminState
+
+from voltha.protos.logical_device_pb2 import LogicalDevice, LogicalPort
+from voltha.protos.openflow_13_pb2 import ofp_desc, ofp_port, OFPPF_10GB_FD, \
+ OFPPF_FIBER, OFPPS_LIVE, ofp_switch_features, OFPC_PORT_STATS, \
+ OFPC_GROUP_STATS, OFPC_TABLE_STATS, OFPC_FLOW_STATS
+
+from scapy.packet import Packet, bind_layers
+from scapy.fields import StrField
+
+log = structlog.get_logger()
+
+from voltha.extensions.eoam.EOAM_TLV import AddStaticMacAddress, DeleteStaticMacAddress
+from voltha.extensions.eoam.EOAM_TLV import ClearStaticMacTable
+from voltha.extensions.eoam.EOAM_TLV import DeviceId
+from voltha.extensions.eoam.EOAM_TLV import ClauseSubtypeEnum
+from voltha.extensions.eoam.EOAM_TLV import RuleOperatorEnum
+from voltha.extensions.eoam.EOAM_TLV import FirmwareInfo
+
+from voltha.extensions.eoam.EOAM import EOAMPayload, CablelabsOUI
+from voltha.extensions.eoam.EOAM import DPoEOpcode_GetRequest, DPoEOpcode_SetRequest
+
+@implementer(IAdapterInterface)
+class DPoEOnuAdapter(object):
+
+ name = 'dpoe_onu'
+
+ supported_device_types = [
+ DeviceType(
+ id='dpoe_onu',
+ adapter=name,
+ accepts_bulk_flow_update=True
+ )
+ ]
+
+ def __init__(self, adapter_agent, config):
+ self.adapter_agent = adapter_agent
+ self.config = config
+ self.descriptor = Adapter(
+ id=self.name,
+ vendor='Sumitomo Electric, Inc.',
+ version='0.1',
+ config=AdapterConfig(log_level=LogLevel.INFO)
+ )
+ self.incoming_messages = DeferredQueue()
+
+ def start(self):
+ log.debug('starting')
+ log.info('started')
+
+ def stop(self):
+ log.debug('stopping')
+ log.info('stopped')
+
+ def adapter_descriptor(self):
+ return self.descriptor
+
+ def device_types(self):
+ return DeviceTypes(items=self.supported_device_types)
+
+ def health(self):
+ return HealthStatus(state=HealthStatus.HealthState.HEALTHY)
+
+ def change_master_state(self, master):
+ raise NotImplementedError()
+
+ def adopt_device(self, device):
+ log.info('adopt-device', device=device)
+ reactor.callLater(0.1, self._onu_device_activation, device)
+ return device
+
+ @inlineCallbacks
+ def _onu_device_activation(self, device):
+ # first we verify that we got parent reference and proxy info
+ assert device.parent_id
+ assert device.proxy_address.device_id
+ assert device.proxy_address.channel_id
+
+ # TODO: For now, pretend that we were able to contact the device and obtain
+ # additional information about it. Should add real message.
+ device.vendor = 'Sumitomo Electric, Inc.'
+ device.model = '10G EPON ONU'
+ device.hardware_version = 'fa161020'
+ device.firmware_version = '16.12.02'
+ device.software_version = '1.0'
+ device.serial_number = uuid4().hex
+ device.connect_status = ConnectStatus.REACHABLE
+ self.adapter_agent.update_device(device)
+
+ # then shortly after we create some ports for the device
+ uni_port = Port(
+ port_no=2,
+ label='UNI facing Ethernet port',
+ type=Port.ETHERNET_UNI,
+ admin_state=AdminState.ENABLED,
+ oper_status=OperStatus.ACTIVE
+ )
+ self.adapter_agent.add_port(device.id, uni_port)
+ self.adapter_agent.add_port(device.id, Port(
+ port_no=1,
+ label='PON port',
+ type=Port.PON_ONU,
+ admin_state=AdminState.ENABLED,
+ oper_status=OperStatus.ACTIVE,
+ peers=[
+ Port.PeerPort(
+ device_id=device.parent_id,
+ port_no=device.parent_port_no
+ )
+ ]
+ ))
+
+ # TODO adding vports to the logical device shall be done by agent?
+ # then we create the logical device port that corresponds to the UNI
+ # port of the device
+
+ # obtain logical device id
+ parent_device = self.adapter_agent.get_device(device.parent_id)
+ logical_device_id = parent_device.parent_id
+ assert logical_device_id
+
+ # we are going to use the proxy_address.channel_id as unique number
+ # and name for the virtual ports, as this is guaranteed to be unique
+ # in the context of the OLT port, so it is also unique in the context
+ # of the logical device
+ port_no = device.proxy_address.channel_id
+ cap = OFPPF_10GB_FD | OFPPF_FIBER
+ self.adapter_agent.add_logical_port(logical_device_id, LogicalPort(
+ id=str(port_no),
+ ofp_port=ofp_port(
+ port_no=port_no,
+ hw_addr=mac_str_to_tuple(device.mac_address),
+ name='uni-{}'.format(port_no),
+ config=0,
+ state=OFPPS_LIVE,
+ curr=cap,
+ advertised=cap,
+ peer=cap,
+ curr_speed=OFPPF_10GB_FD,
+ max_speed=OFPPF_10GB_FD
+ ),
+ device_id=device.id,
+ device_port_no=uni_port.port_no
+ ))
+
+ # simulate a proxied message sending and receving a reply
+ reply = yield self._message_exchange(device)
+
+ # and finally update to "ACTIVE"
+ device = self.adapter_agent.get_device(device.id)
+ device.oper_status = OperStatus.ACTIVE
+ self.adapter_agent.update_device(device)
+
+ def abandon_device(self, device):
+ raise NotImplementedError(0
+ )
+ def deactivate_device(self, device):
+ raise NotImplementedError()
+
+ def update_flows_bulk(self, device, flows, groups):
+ log.info('########################################')
+ log.info('bulk-flow-update', device_id=device.id,
+ flows=flows, groups=groups)
+ assert len(groups.items) == 0, "Cannot yet deal with groups"
+
+ Clause = {v: k for k, v in ClauseSubtypeEnum.iteritems()}
+ Operator = {v: k for k, v in RuleOperatorEnum.iteritems()}
+
+ for flow in flows.items:
+ in_port = get_in_port(flow)
+ assert in_port is not None
+
+ precedence = 255 - min(flow.priority / 256, 255)
+
+ if in_port == 2:
+ log.info('#### Downstream Rule ####')
+ dn_req = EOAMPayload(body=CablelabsOUI() /
+ DPoEOpcode_SetRequest())
+
+ for field in get_ofb_fields(flow):
+
+ if field.type == ETH_TYPE:
+ _type = field.eth_type
+ log.info('#### field.type == ETH_TYPE ####',field_type=_type)
+
+ elif field.type == IP_PROTO:
+ _proto = field.ip_proto
+ log.info('#### field.type == IP_PROTO ####')
+ pass # construct ip_proto based condition here
+
+ elif field.type == IN_PORT:
+ _port = field.port
+ log.info('#### field.type == IN_PORT ####', port=_port)
+ pass # construct in_port based condition here
+
+ elif field.type == VLAN_VID:
+ _vlan_vid = field.vlan_vid & 0xfff
+ log.info('#### field.type == VLAN_VID ####', vlan=_vlan_vid)
+
+ elif field.type == VLAN_PCP:
+ _vlan_pcp = field.vlan_pcp
+ log.info('#### field.type == VLAN_PCP ####', pcp=_vlan_pcp)
+ pass # construct VLAN PCP based filter condition here
+
+ elif field.type == UDP_DST:
+ _udp_dst = field.udp_dst
+ log.info('#### field.type == UDP_DST ####')
+ pass # construct UDP SDT based filter here
+
+ elif field.type == IPV4_DST:
+ _ipv4_dst = field.ipv4_dst
+ log.info('#### field.type == IPV4_DST ####')
+ pass
+
+ else:
+ log.info('#### field.type == NOT IMPLEMENTED!! ####')
+ raise NotImplementedError('field.type={}'.format(
+ field.type))
+
+ for action in get_actions(flow):
+
+ if action.type == OUTPUT:
+ log.info('#### action.type == OUTPUT ####')
+
+ elif action.type == POP_VLAN:
+ log.info('#### action.type == POP_VLAN ####')
+ pass # construct vlan pop command here
+
+ elif action.type == PUSH_VLAN:
+ log.info('#### action.type == PUSH_VLAN ####')
+ if action.push.ethertype != 0x8100:
+ log.error('unhandled-tpid',
+ ethertype=action.push.ethertype)
+
+ elif action.type == SET_FIELD:
+ log.info('#### action.type == SET_FIELD ####')
+ assert (action.set_field.field.oxm_class ==
+ ofp.OFPXMC_OPENFLOW_BASIC)
+ field = action.set_field.field.ofb_field
+ if field.type == VLAN_VID:
+ pass
+ else:
+ log.error('unsupported-action-set-field-type',
+ field_type=field.type)
+ else:
+ log.error('UNSUPPORTED-ACTION-TYPE',
+ action_type=action.type)
+
+ # send message
+ log.info('ONU-send-proxied-message')
+# self.adapter_agent.send_proxied_message(device.proxy_address, dn_req)
+
+
+ elif in_port == 1:
+ # Upstream rule
+ log.info('#### Upstream Rule ####')
+
+ #### Loop through fields again...
+
+ for field in get_ofb_fields(flow):
+
+ if field.type == ETH_TYPE:
+ _type = field.eth_type
+ log.info('#### field.type == ETH_TYPE ####', in_port=in_port,
+ match=_type)
+
+ elif field.type == IP_PROTO:
+ _proto = field.ip_proto
+ log.info('#### field.type == IP_PROTO ####', in_port=in_port,
+ ip_proto=ip_proto)
+
+ elif field.type == IN_PORT:
+ _port = field.port
+ log.info('#### field.type == IN_PORT ####')
+ pass # construct in_port based condition here
+
+ elif field.type == VLAN_VID:
+ _vlan_vid = field.vlan_vid & 0xfff
+ log.info('#### field.type == VLAN_VID ####')
+
+ elif field.type == VLAN_PCP:
+ _vlan_pcp = field.vlan_pcp
+ log.info('#### field.type == VLAN_PCP ####')
+ pass # construct VLAN PCP based filter condition here
+
+ elif field.type == UDP_DST:
+ _udp_dst = field.udp_dst
+ log.info('#### field.type == UDP_DST ####')
+
+ else:
+ raise NotImplementedError('field.type={}'.format(
+ field.type))
+
+ for action in get_actions(flow):
+
+ if action.type == OUTPUT:
+ log.info('#### action.type == OUTPUT ####')
+
+ elif action.type == POP_VLAN:
+ log.info('#### action.type == POP_VLAN ####')
+ pass # construct vlan pop command here
+
+ elif action.type == PUSH_VLAN:
+ log.info('#### action.type == PUSH_VLAN ####')
+ if action.push.ethertype != 0x8100:
+ log.error('unhandled-ether-type',
+ ethertype=action.push.ethertype)
+
+ elif action.type == SET_FIELD:
+ log.info('#### action.type == SET_FIELD ####')
+ assert (action.set_field.field.oxm_class ==
+ ofp.OFPXMC_OPENFLOW_BASIC)
+ field = action.set_field.field.ofb_field
+ if field.type == VLAN_VID:
+ pass
+ else:
+ log.error('unsupported-action-set-field-type',
+ field_type=field.type)
+
+ else:
+ log.error('UNSUPPORTED-ACTION-TYPE',
+ action_type=action.type)
+
+ else:
+ raise Exception('Port should be 1 or 2 by our convention')
+
+ def update_flows_incrementally(self, device, flow_changes, group_changes):
+ raise NotImplementedError()
+
+ def send_proxied_message(self, proxy_address, msg):
+ raise NotImplementedError()
+
+ def receive_proxied_message(self, proxy_address, msg):
+ log.debug('receive-proxied-message',
+ proxy_address=proxy_address, msg=msg)
+ self.incoming_messages.put(msg)
+
+ @inlineCallbacks
+ def _message_exchange(self, device):
+
+ # register for receiving async messages
+ self.adapter_agent.register_for_proxied_messages(device.proxy_address)
+
+ # reset incoming message queue
+ while self.incoming_messages.pending:
+ _ = yield self.incoming_messages.get()
+
+ # construct message
+ msg = EOAMPayload(body=CablelabsOUI() /
+ DPoEOpcode_GetRequest() /
+ DeviceId()
+ )
+
+ # send message
+ log.info('ONU-send-proxied-message')
+ self.adapter_agent.send_proxied_message(device.proxy_address, msg)
+
+ # wait till we detect incoming message
+ yield self.incoming_messages.get()
+
+ # construct install of igmp query address
+ msg = EOAMPayload(body=CablelabsOUI() /
+ DPoEOpcode_SetRequest() /
+ AddStaticMacAddress(mac='01:00:5e:00:00:01')
+ )
+
+ # send message
+ log.info('ONU-send-proxied-message')
+ self.adapter_agent.send_proxied_message(device.proxy_address, msg)
+
+ # wait till we detect incoming message
+ yield self.incoming_messages.get()
+
+ # construct install of igmp query address
+ msg = EOAMPayload(body=CablelabsOUI() /
+ DPoEOpcode_GetRequest() /
+ FirmwareInfo()
+ )
+
+ # send message
+ log.info('ONU-send-proxied-message')
+ self.adapter_agent.send_proxied_message(device.proxy_address, msg)
+
+ # wait till we detect incoming message
+ yield self.incoming_messages.get()
+
+ # by returning we allow the device to be shown as active, which
+ # indirectly verified that message passing works
+
+ def receive_packet_out(self, logical_device_id, egress_port_no, msg):
+ log.info('packet-out', logical_device_id=logical_device_id,
+ egress_port_no=egress_port_no, msg_len=len(msg))
diff --git a/voltha/adapters/dpoe_onu/eoam_config.py b/voltha/adapters/dpoe_onu/eoam_config.py
new file mode 100644
index 0000000..b69770b
--- /dev/null
+++ b/voltha/adapters/dpoe_onu/eoam_config.py
@@ -0,0 +1,358 @@
+#!/usr/bin/env python
+#--------------------------------------------------------------------------#
+# Copyright (C) 2015 - 2016 by Tibit Communications, Inc. #
+# All rights reserved. #
+# #
+# _______ ____ _ ______ #
+# /_ __(_) __ )(_)_ __/ #
+# / / / / __ / / / / #
+# / / / / /_/ / / / / #
+# /_/ /_/_____/_/ /_/ #
+# #
+#--------------------------------------------------------------------------#
+""" EOAM protocol implementation in scapy """
+
+TIBIT_VERSION_NUMBER = '1.1.2'
+
+import time
+import logging
+import argparse
+import sys
+import inspect
+
+logging.getLogger("scapy.runtime").setLevel(logging.ERROR)
+from scapy.all import Dot1Q
+from scapy.all import sniff
+from scapy.all import IP, UDP
+from scapy.packet import Packet, bind_layers
+from scapy.fields import StrField
+from scapy.layers.l2 import Ether
+from scapy.main import interact
+from scapy.sendrecv import sendp
+from scapy.sendrecv import srp1
+from scapy.config import conf
+conf.verb = None
+
+import fcntl, socket, struct # for get hw address
+
+# TODO should remove import *
+from EOAM_TLV import *
+
+EOAM_MULTICAST_ADDRESS = '01:80:c2:00:00:02'
+IGMP_MULTICAST_ADDRESS = '01:00:5e:00:00:01' # for test
+
+class EOAM():
+ """ EOAM frame layer """
+ def __init__(self, ctag=None, dryrun=False, stag=None,
+ verbose=False, etype='8809',
+ dst=EOAM_MULTICAST_ADDRESS,
+ hexdump=False, interface='eth0',
+ sleep=1.0):
+ self.verbose = verbose
+ self.dst = dst
+ self.dryrun = dryrun
+ self.hexdump = hexdump
+ self.interface = interface
+ self.etype = int(etype, 16)
+ self.stag = stag
+ self.ctag = ctag
+ self.sleep = sleep
+ if (self.verbose == True):
+ print("=== Settings ================")
+ print("ctag = %s" % self.ctag)
+ print("stag = %s" % self.stag)
+ print("dst = %s" % self.dst)
+ print("dryrun = %s" % self.dryrun)
+ print("hexdump = %s" % self.hexdump)
+ print("interface = %s" % self.interface)
+ print("etype = 0x%04x" % self.etype)
+ print("verbose = %s" % self.verbose)
+ print("=== END Settings ============")
+
+ def send_frame(self, frame_body):
+ PACKET = Ether()
+ PACKET.length = 64
+ PACKET.dst = self.dst
+ PACKET.src = self.getHwAddr(self.interface)
+ if self.stag:
+ # WARNING: September/2016: This should be 0x88a8, but the Intel 10G
+ # hardware I am currently using does not support receiving a TPID of
+ # 0x88a8. So, I send double CTAGs, and I usually set this to 0x8100.
+ # (NOTE: The Intel hardware can send a TPID of 0x88a8)
+ PACKET.type = 0x8100
+ if self.ctag:
+ PACKET/=Dot1Q(type=0x8100,vlan=int(self.stag))
+ PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))
+ else:
+ PACKET/=Dot1Q(type=self.etype,vlan=int(self.stag))
+ else:
+ if self.ctag:
+ PACKET.type = 0x8100
+ PACKET/=Dot1Q(type=self.etype,vlan=int(self.ctag))
+ else:
+ PACKET.type = self.etype
+# PACKET/=Dot1Q(type=self.etype, vlan=int(self.ctag))
+ PACKET/=SlowProtocolsSubtype()/FlagsBytes()/OAMPDU()
+ PACKET/=frame_body
+ PACKET/=EndOfPDU()
+ if (self.verbose == True):
+ PACKET.show()
+ print '###[ Frame Length %d (before padding) ]###' % len(PACKET)
+ if (self.hexdump == True):
+ print hexdump(PACKET)
+ if (self.dryrun != True):
+ sendp(PACKET, iface=self.interface, verbose=self.verbose)
+ time.sleep(self.sleep)
+ return PACKET
+
+ def get_request(self, TLV):
+ return self.send_frame(CablelabsOUI()/DPoEOpcode_GetRequest()/TLV)
+
+ def set_request(self, TLV):
+ return self.send_frame(CablelabsOUI()/DPoEOpcode_SetRequest()/TLV)
+
+ def send_multicast_register(self, TLV):
+ '''
+ Note, for mulicast, the standard specifies a register message
+ with ActionFlags of either Register or Deregister
+ '''
+ return self.send_frame(CablelabsOUI()/DPoEOpcode_MulticastRegister()/TLV)
+
+ def set_request_broadcom(self, TLV):
+ return self.send_frame(BroadcomOUI()/DPoEOpcode_SetRequest()/TLV)
+
+ def getHwAddr(self, ifname):
+ if (not self.dryrun):
+ s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
+ info = fcntl.ioctl(s.fileno(), 0x8927, struct.pack('256s', ifname[:15]))
+ else:
+ info = range(1, 24)
+ info[18:24] = ['0','1','2','3','4','5']
+
+ return ':'.join(['%02x' % ord(char) for char in info[18:24]])
+
+
+if __name__ == "__main__":
+ parser = argparse.ArgumentParser()
+ parser.add_argument('-d', '--dst', dest='dst', action='store', default=EOAM_MULTICAST_ADDRESS,
+ help='MAC destination (default: %s)' % EOAM_MULTICAST_ADDRESS)
+ parser.add_argument('-e', '--etype', dest='etype', action='store', default='8809',
+ help='EtherType value (default: 0x8809)')
+ parser.add_argument('-i', '--interface', dest='interface', action='store', default='eth0',
+ help='ETH interface to send (default: eth0)')
+ parser.add_argument('-s', '--stag', dest='stag', action='store', default=None,
+ help='STAG value (default: None)')
+ parser.add_argument('-c', '--ctag', dest='ctag', action='store', default=None,
+ help='CTAG value (default: None)')
+ parser.add_argument('-p', '--sleep', dest='sleep', action='store', default='1.0', type=float,
+ help='SLEEP time after frame (default: 0.5 secs)')
+ parser.add_argument('-v', '--verbose', dest='verbose', action='store_true', default=False,
+ help='verbose frame print out')
+ parser.add_argument('-x', '--hexdump', dest='hexdump', action='store_true', default=False,
+ help='Hexdump the frame')
+ parser.add_argument('-y', '--dryrun', dest='dryrun', action='store_true', default=False,
+ help='Dry run test, dont send - just print')
+
+ parser.add_argument('-t', '--test', dest='test', action='store_true', default=False,
+ help='Run commands under test')
+ parser.add_argument('-r', '--critical', dest='critical', action='store_true', default=False,
+ help='Send the critical OAM set of set_request()')
+ parser.add_argument('-ta', '--test_add', dest='test_add', action='store_true', default=False,
+ help='Run commands under test')
+ parser.add_argument('-td', '--test_del', dest='test_del', action='store_true', default=False,
+ help='Run commands under test')
+ parser.add_argument('-tc', '--test_clr', dest='test_clr', action='store_true', default=False,
+ help='Run commands under test')
+
+ args = parser.parse_args()
+
+ if (args.dryrun == True):
+ args.sleep = 0.0
+
+ eoam = EOAM(
+ dryrun=args.dryrun,
+ dst=args.dst,
+ etype=args.etype,
+ hexdump=args.hexdump,
+ interface=args.interface,
+ stag=args.stag,
+ ctag=args.ctag,
+ verbose=args.verbose,
+ )
+
+ if (not args.critical
+ and not args.test
+ and not args.test_add
+ and not args.test_del
+ and not args.test_clr):
+ print 'WARNING: *** No frames sent, please specify \'test\' or \'critical\', etc. See --help'
+
+ # Critical OAM Messages
+ if (args.critical == True):
+
+ # OAM GET Requests
+ print 'GET DeviceId and MAX Logical Links Message'
+ eoam.get_request(DeviceId()/MaxLogicalLinks())
+
+ print 'SET Report Thresholds Message'
+ eoam.set_request(ReportThresholdsSet())
+
+ print 'SET OAM Frame Rate Message'
+ eoam.set_request(OamFrameRateSet())
+
+ print 'GET multiple - Device and Manufacturing Info'
+ eoam.get_request(DONUObject()/DeviceId()/MaxLogicalLinks()/
+ FirmwareInfo()/ChipsetInfo()/NumberOfNetworkPorts()/NumberOfS1Interfaces())
+
+ print 'GET - LLID Queue Configuration'
+ eoam.get_request(DONUObject()/LLIDQueueConfiguration())
+
+ print 'GET - ONU Manufacturer Organization Name'
+ eoam.get_request(DONUObject()/OnuManufacturerOrganizationName())
+
+ print 'GET - ONU Firmware Mfg Time Varying Controls'
+ eoam.get_request(DONUObject()/FirmwareMfgTimeVaryingControls())
+
+ print 'GET - ONU Vendor Name'
+ eoam.get_request(DONUObject()/VendorName())
+
+ print 'GET - ONU Model Number'
+ eoam.get_request(DONUObject()/ModelNumber())
+
+ print 'GET - ONU Hardware Version'
+ eoam.get_request(DONUObject()/HardwareVersion())
+
+ print 'SET - Clear Port Ingress Rules -- Network Port Object'
+ eoam.set_request(NetworkPortObject()/ClearPortIngressRules())
+
+ print 'SET - Clear Port Ingress Rules -- User Port Object'
+ eoam.set_request(UserPortObject()/ClearPortIngressRules())
+
+ print 'SET - Broadcom Specific TLVs'
+ eoam.set_request_broadcom(Broadcom07_7F_F1_Set01()/Broadcom07_7F_F1_Set02()/
+ Broadcom07_7F_F1_Set03()/Broadcom07_7F_F1_Set04())
+
+ print 'SET - Multicast Register Message 01'
+ eoam.send_multicast_register(MulticastRegisterSetSumitomo01())
+
+ print 'SET - Multicast Register Message 02'
+ eoam.send_multicast_register(MulticastRegisterSetSumitomo02())
+
+ print 'SET - Custom Field EtherType'
+ eoam.set_request(UserPortObject()/CustomFieldEtherType())
+
+ print 'SET - Custom Field Generic L3'
+ eoam.set_request(UserPortObject()/CustomFieldGenericL3())
+
+ print 'SET - MAC Learning MIN/MAX/Age Limit -- User Port Object'
+ eoam.set_request(UserPortObject()/MacLearningMaxAllowedSet()/DynamicAddressAgeLimitSet()/
+ SourceAddressAdmissionControlSet()/MacLearningMinGuaranteeSet())
+
+ print 'SET - MAC Learning/Flooding/Local Switching -- D-ONU Port Object'
+ eoam.set_request(DONUObject()/MacLearningAggregateLimitSet()/FloodUnknownSet()/LocalSwitchingSet())
+
+ print 'SET - Report Thresholds -- Unicast Logical Link'
+ eoam.set_request(UnicastLogicalLink()/UnicastLogicalLinkReportThresholdsSet())
+
+ print 'SET - Port Ingress Rule -- Network Port Object -- Precedence 12'
+ eoam.set_request(NetworkPortObject()/
+ PortIngressRuleHeader(precedence=12)/
+ PortIngressRuleClauseMatchLength01(operator=1)/
+ PortIngressRuleResultForward()/
+ PortIngressRuleResultQueue(objecttype=0x0003)/
+ PortIngressRuleTerminator()/
+ AddPortIngressRule())
+
+ print 'SET - Port Ingress Rule -- User Port Object -- Precedence 13'
+ eoam.set_request(UserPortObject()/
+ PortIngressRuleHeader(precedence=13)/
+ PortIngressRuleClauseMatchLength00(fieldcode=1, operator=7)/
+ PortIngressRuleResultQueue(objecttype=0x0002)/
+ PortIngressRuleTerminator()/
+ AddPortIngressRule())
+
+ print 'SET - Port Ingress Rule -- User Port Object -- Precedence 7 Discard 01'
+ eoam.set_request(UserPortObject()/
+ PortIngressRuleHeader(precedence=7)/
+ PortIngressRuleClauseMatchLength06(fieldcode=1, operator=1)/
+ PortIngressRuleResultDiscard()/
+ PortIngressRuleTerminator()/
+ AddPortIngressRule())
+
+
+ print 'SET - Port Ingress Rule -- User Port Object -- Precedence 7 Discard 02'
+ eoam.set_request(UserPortObject()/
+ PortIngressRuleHeader(precedence=7)/
+ PortIngressRuleClauseMatchLength06(fieldcode=1, operator=1, match5=0x02)/
+ PortIngressRuleClauseMatchLength02(fieldcode=0x19, operator=1, match=0x8889)/
+ PortIngressRuleClauseMatchLength01(fieldcode=0x1a, operator=1, match=0x03)/
+ PortIngressRuleResultDiscard()/
+ PortIngressRuleTerminator()/
+ AddPortIngressRule())
+
+ print 'GET - D-ONU Object -- Firmware Filename'
+ eoam.set_request(DONUObject()/FirmwareFilename())
+
+ print 'SET - User Port Object 0 -- Broadcom Specific TLVs'
+ eoam.set_request_broadcom(UserPortObject(number=0)/Broadcom07_7F_F6_Set())
+
+ print 'SET - User Port Object 1 -- Broadcom Specific TLVs'
+ eoam.set_request_broadcom(UserPortObject(number=1)/Broadcom07_7F_F6_Set())
+
+ print 'SET - User Port Object 0 -- Clause 30 Attributes -- MAC Enable'
+ eoam.set_request(UserPortObject()/Clause30AttributesMacEnable())
+
+ print 'SET - IPMC Forwarding Rule Configuration'
+ eoam.set_request(IpmcForwardingRuleConfiguration())
+
+ print 'SET - Enable User Traffic -- Unicast Logical Link'
+ eoam.set_request(UnicastLogicalLink()/EnableUserTraffic())
+
+ if (args.test == True):
+ print 'SET - Multicast Register Message 01'
+ eoam.send_multicast_register(MulticastRegisterSet(MulticastLink=0x3ff0, UnicastLink=0x120f))
+
+ #print 'SET - Multicast Deregister Message 02'
+ eoam.send_multicast_register(MulticastRegisterSet(ActionFlags="Deregister",MulticastLink=0x3ff0, UnicastLink=0x120f))
+
+ if (args.test_clr == True):
+ print 'SET Clear Static MAC Table -- User Port Object'
+ eoam.set_request(ClearStaticMacTable())
+
+ elif (args.test_add == True):
+ print 'SET Add Static MAC Address -- User Port Object'
+ eoam.set_request(AddStaticMacAddress(mac=IGMP_MULTICAST_ADDRESS))
+
+ elif (args.test_del == True):
+ print 'SET Delete Static MAC Address -- User Port Object'
+ eoam.set_request(DeleteStaticMacAddress(mac=IGMP_MULTICAST_ADDRESS))
+
+
+
+ # EXTERNAL OAM LIB TESTING
+ #import tboam
+ #tboam.get_request(f.branch, f.leaf)
+ #print 'SET - User Port Object 1 -- Broadcom Specific TLVs'
+ #f = eoam.set_request_broadcom(UserPortObject(number=1)/Broadcom07_7F_F6_Set())
+ #print("=== receive frame ===========")
+ #Now, pretend I just received this frame.
+ #f.show()
+ #tboam.set_request(f.branch, f.leaf)
+
+ # Examples
+ #oam_frame = eoam.get_request(UserPortObject()/LoopbackEnable())
+ #oam_frame = eoam.get_reqeust(UserPortObject()/LoopbackDisable())
+ #oam_frame = eoam.set_request(UserPortObject()/LoopbackEnable())
+ #oam_frame = eoam.set_request(UnicastLogicalLink()/AlarmReportingSet())
+ #oam_frame = eoam.get_request(UserPortObject()/BytesDropped())
+ #oam_frame = eoam.get_request(UserPortObject()/TxBytesUnused())
+ #print 'GET -- User Port Object -- Rx Frame 512-1023'
+ #oam_frame = eoam.get_request(UserPortObject()/RxFrame_512_1023())
+ #print 'GET -- User Port Object -- Tx Frame 512-1023'
+ #oam_frame = eoam.get_request(UserPortObject()/TxFrame_512_1023())
+ #oam_frame = eoam.get_request(NetworkPortObject()/BytesDropped())
+ #oam_frame = eoam.get_request(NetworkPortObject()/TxBytesUnused())
+ #print 'GET -- Network Port Object -- Rx Frame 512-1023'
+ #oam_frame = eoam.get_request(NetworkPortObject()/RxFrame_512_1023())
+ #print 'GET -- Network Port Object -- Tx Frame 512-1023'
+ #oam_frame = eoam.get_request(NetworkPortObject()/TxFrame_512_1023())
diff --git a/voltha/adapters/dpoe_onu/mgmt_json.c b/voltha/adapters/dpoe_onu/mgmt_json.c
new file mode 100644
index 0000000..4391a4f
--- /dev/null
+++ b/voltha/adapters/dpoe_onu/mgmt_json.c
@@ -0,0 +1,2202 @@
+/*--------------------------------------------------------------------------*/
+/* Copyright (C) 2015 - 2016 by Tibit Communications, Inc. */
+/* All rights reserved. */
+/* */
+/* _______ ____ _ ______ */
+/* /_ __(_) __ )(_)_ __/ */
+/* / / / / __ / / / / */
+/* / / / / /_/ / / / / */
+/* /_/ /_/_____/_/ /_/ */
+/* */
+/*--------------------------------------------------------------------------*/
+/* PROPRIETARY NOTICE */
+/* This Software consists of confidential information. */
+/* Trade secret law and copyright law protect this Software. */
+/* The above notice of copyright on this Software does not indicate */
+/* any actual or intended publication of such Software. */
+/*--------------------------------------------------------------------------*/
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <errno.h>
+#include <common.h>
+#include <cli.h>
+#include <command.h>
+#include <assert.h>
+
+#include "tb_dbug.h"
+#include "tb_port.h"
+#include "tb_util.h"
+#include "tb_global.h"
+#include "tb_types.h"
+
+#include "cli_version.h"
+#include "mgmt_json.h"
+#include "brdg.h"
+#include "os_interface.h"
+#include "jsmn.h"
+
+#include "olt_fsm.h"
+#include "onu_fsm.h"
+#include "eth_fsm.h"
+#include "hal_llid.h"
+#include "hal_frame.h"
+#include "switching.h"
+
+#include "ieee_802.3.h"
+
+
+/*--- global variables -----------------------------------------------------*/
+static tb_pkt_deprec_t fake_frame; /* for commands from the CLI */
+extern const char *brdg_stat_name_lower[];
+extern const char *brdg_stat_total_lower[];
+static bool command_line_json = false;
+
+/*--- definitions ----------------------------------------------------------*/
+#define FRAME_CRC_SIZE 4
+#define VLAN_HEADER_BYTES 4
+
+#define START_OF_JSON_VLAN (27 + (VLAN_HEADER_BYTES))
+#define START_OF_JSON_UNTAGGED (27)
+#define COPY_TYPE 0x636f7079 // 'copy'
+#define DNLD_TYPE 0x646e6c64 // 'dnld'
+#define JSON_TYPE 0x6a736f6e /* ASCII HEX 'json' */
+#define JSON_MAX_INTERFACES 5
+typedef enum json_string_print { APPEND, APPEND_AND_FLUSH, APPEND_AND_FLUSH_CR,
+ RESET
+} json_string_print_t;
+
+/*--- function prototypes --------------------------------------------------*/
+void hw_reset(void);
+int set_sernum_and_mac_address(unsigned int);
+static int dump(const char *js, jsmntok_t * t, size_t count, int indent);
+static int remove_backslashes(char *working, uint8_t * p_buffer, unsigned int length);
+
+/*--- more globals ---------------------------------------------------------*/
+static char global_json_string[SIZE_OF_JSON_STRING] = { '\0' };
+
+static char operation[SIZE_OF_OPERATION] = { '\0' };
+static char location[SIZE_OF_ADDRESS] = { '\0' };
+static char value[SIZE_OF_VALUE] = { '\0' };
+static char llid[SIZE_OF_LLID] = { '\0' };
+static char macblock[SIZE_OF_MACBLOCK] = { '\0' };
+static char itype[SIZE_OF_ITYPE] = { '\0' };
+static char iinst[SIZE_OF_IINST] = { '\0' };
+static char mac[MAC_STR_LEN] = { '\0' };
+static char swr[SIZE_OF_SWR] = { '\0' };
+static char cmd[SIZE_OF_CMD] = { '\0' };
+
+#define SVID_STR_LEN 5
+#define CVID_STR_LEN 5
+static char svid[SVID_STR_LEN] = { '\0' };
+static char cvid[CVID_STR_LEN] = { '\0' };
+
+static mac_address mac_addr;
+#define CIR_STR_LEN 12
+#define EIR_STR_LEN 12
+static char cir[CIR_STR_LEN] = { '\0' };
+static char eir[EIR_STR_LEN] = { '\0' };
+
+#define CODE_STR_LEN 5
+static char code[CODE_STR_LEN] = { '\0' };
+
+#define TPID_STR_LEN 5
+static char tpid[TPID_STR_LEN] = { '\0' };
+
+#define VID_STR_LEN 5
+static char vid[VID_STR_LEN] = { '\0' };
+
+#define MODE_STR_LEN 9
+static char mode[MODE_STR_LEN] = { '\0' };
+
+#define TAG_MODE_STR_LEN 5
+static char tag_mode[TAG_MODE_STR_LEN] = { '\0' };
+
+/*--- more function prototypes ---------------------------------------------*/
+static int process_copy(const uint8_t *, uint32);
+static int process_dnld(const uint8_t *, uint32);
+static int process_json(tb_pkt_deprec_t *);
+static int json_error(tb_pkt_deprec_t *, brdg_return_t);
+static int json_version(tb_pkt_deprec_t *);
+static int json_interfaces(tb_pkt_deprec_t *);
+static int json_links(tb_pkt_deprec_t *, char *, tb_ifc_inst_t);
+static int json_register_read(tb_pkt_deprec_t *, unsigned int address);
+static int json_register_write(tb_pkt_deprec_t *, unsigned int address, unsigned int value);
+static int json_stats(tb_pkt_deprec_t *, unsigned int llid, unsigned int macblock);
+static tb_rc json_tag_mode_get(tb_pkt_deprec_t * rx_frame);
+static tb_rc json_tag_mode_set(tb_pkt_deprec_t * rx_frame, char * tag_mode);
+static tb_rc json_fec_set(tb_pkt_deprec_t * rx_frame, tb_ifc_key_t * ifc_key, bool);
+static tb_rc json_fec_get(tb_pkt_deprec_t * rx_frame, tb_ifc_key_t * ifc_key);
+static tb_rc json_sla_set(tb_pkt_deprec_t * rx_frame, lsm_link_key_t * link_key,
+ lsm_link_sla_spec_t * sla_spec);
+static tb_rc json_sla_get(tb_pkt_deprec_t * rx_frame, lsm_link_key_t * link_key,
+ lsm_link_sla_spec_t * sla_spec);
+static tb_rc json_flows_add(tb_pkt_deprec_t * rx_frame, tb_ifc_key_t * ifc_key,
+ sw_rec_key_t * sw_rec_key, port_vlan_op_cfg_t port_vlan_op_cfg);
+static tb_rc json_flows_delete(tb_pkt_deprec_t * rx_frame, tb_ifc_key_t * ifc_key,
+ sw_rec_key_t * sw_rec_key);
+static tb_rc json_flows_get(tb_pkt_deprec_t * rx_frame);
+static tb_rc json_mode_set(tb_pkt_deprec_t * rx_frame, mandata_pon_type_t mandata_pon);
+static int json_cli_cmd(tb_pkt_deprec_t *);
+
+static int json_str_append_and_out(char *, char *, json_string_print_t, tb_pkt_deprec_t *);
+
+// mac_address mgmt_mac_addr = { .u8 = { 0x08, 0x00, 0x27, 0x63, 0xe8, 0x6e } };
+mac_address mgmt_mac_addr = { .u8 = { 0x84, 0x38, 0x35, 0x4e, 0x9b, 0xb2 } };
+
+void mgmt_mac_addr_set(const mac_address *new_mgmt_mac_addr) {
+ tb_mac_address_str_t old;
+
+ assert(new_mgmt_mac_addr);
+
+ tb_mac_address_to_str(mgmt_mac_addr.u8, old);
+
+ if (0 != memcmp(mgmt_mac_addr.u8, new_mgmt_mac_addr->u8, sizeof(mgmt_mac_addr))) {
+ tb_mac_address_str_t new;
+
+ tb_mac_address_to_str(new_mgmt_mac_addr->u8, new);
+
+ TB_TRACE("updating mgmt_mac_addr %s -> %s", old, new);
+
+ memcpy(mgmt_mac_addr.u8, new_mgmt_mac_addr->u8, sizeof(mgmt_mac_addr));
+ } else {
+ // TB_TRACE("mgmt_mac_addr %s (unchanged)", old);
+ }
+}
+
+void mgmt_mac_addr_get(void *mgmt_mac_addr_dest) {
+ assert(mgmt_mac_addr_dest);
+ memcpy(mgmt_mac_addr_dest, mgmt_mac_addr.u8, sizeof(mgmt_mac_addr));
+}
+
+/**
+ * @brief Forward an OAM Request to the designated MAC Address
+ *
+ * @param rx_frame Pointer to OAM message to be forwarded
+ * @param dst_mac Pointer to Destination MAC Address
+ * @param src_mac Pointer to Source MAC Address
+ * @param oam_start Pointer to Protocol Subtype (0x03 for OAM) in frame
+ * @param onu_vid ONU VID Value
+ *
+ * @return tb_rc
+ */
+static
+tb_rc cli_forward_oam(tb_pkt_deprec_t * rx_frame, mac_address *dst_mac,
+ mac_address *src_mac, const uint8_t *oam_start, uint16_t onu_vid)
+{
+ tb_rc rc = TB_RC_OK;
+
+ unsigned int payload_length = ((unsigned int)rx_frame->num_bytes) - (oam_start - &rx_frame->preamble_start[0]);
+ unsigned int frame_length = 0;
+
+ /* Set destination MAC to EOAM multicast mac */
+ memcpy(&rx_frame->preamble_start[8], &multicast_da_oam, sizeof(mac_address));
+
+ /* Set source MAC to OLT MAC address */
+ memcpy(&rx_frame->preamble_start[14], &tbg.mac_1_address, sizeof(mac_address));
+
+ /* Set the type and copy in the payload */
+ tb_pack_u16(&rx_frame->preamble_start[20], 0x8809);
+
+ /* Zero out CRC on frame just to make sure that it is not be reused */
+ memset(&rx_frame->preamble_start[rx_frame->num_bytes - 4], 0, 4);
+
+ /* Copy in the frame */
+ memcpy(&rx_frame->preamble_start[22], oam_start, payload_length);
+
+ /* NEW Frame Length */
+ frame_length = 6 /* dest */
+ + 6 /* source */
+ + 2 /* type */
+ + payload_length;
+
+ TB_TRACE("tx length %d (w/o preamble)", frame_length);
+ rx_frame->num_bytes = frame_length;
+
+ rc = oam_olt_send_oam_to_onu(rx_frame->preamble_start + 8, frame_length,
+ src_mac, dst_mac, OLT_OAM_ORIGIN_HOST, onu_vid);
+ return rc;
+}
+
+
+tb_rc cli_handle_rx_frame(tb_pkt_deprec_t * rx_frame)
+{
+ tb_rc rc = TB_RC_OK;
+ unsigned int jsonType = 0;
+ const uint8_t *payload_start = &rx_frame->preamble_start[8]; // real payload starts after 8-byte preamble
+ const uint8_t *ethtype_start = payload_start + 2*sizeof(mac_address);
+ const uint8_t *json_start;
+ uint16_t vid = 0;
+ unsigned short ethType = (ethtype_start[0] << 8) | ethtype_start[1];
+
+ mac_address dest_addr;
+ memcpy(dest_addr.u8, payload_start, sizeof(mac_address));
+
+ mac_address remote_addr;
+ memcpy(remote_addr.u8, payload_start+sizeof(mac_address), sizeof(mac_address));
+ mgmt_mac_addr_set((const mac_address *)(payload_start+sizeof(mac_address)));
+
+ tb_mac_address_str_t remote_addr_str;
+ tb_mac_address_to_str(remote_addr.u8, remote_addr_str);
+
+ tb_dbug_hexdump_one_line(TB_DBUG_LVL_DEBUG, __FUNCTION__, __LINE__, rx_frame->preamble_start, 0, rx_frame->num_bytes+8, COLOR_RED "Frame: " COLOR_OFF , "<---");
+
+ TB_DEBUG("payload_start %p remote %s ethtype_start %p ethtype %04x num_bytes %u rx_que %u tx_que %u data %08lx", payload_start, remote_addr_str, ethtype_start, ethType, rx_frame->num_bytes, rx_frame->rx_que, rx_frame->tx_que, (uint32_t) rx_frame->data);
+
+ while ((0x88a8 == ethType) || (0x8100 == ethType)) {
+ vid = ((ethtype_start[2] << 8) | ethtype_start[3]) & 0xfff;
+ TB_TRACE("skipping %c-tag, value %04d (0x%03x), ethtype_start %p -> %p",
+ (0x88a8 == ethType) ? 'S' : 'C',
+ vid, vid,
+ ethtype_start,
+ ethtype_start+4);
+
+ ethtype_start += 4;
+ ethType = (ethtype_start[0] << 8) | ethtype_start[1];
+ }
+ json_start = ethtype_start + 2;
+ if (ethType != 0x9001) {
+ TB_WARNING("FRAME ETHERTYPE NOT 0x9001");
+ TB_ERROR("ethtype 0x%04x (actual) vs. 0x9001 (expected)", ethType);
+ tb_dbug_hexdump_one_line(TB_DBUG_LVL_ERROR, __FUNCTION__, __LINE__,
+ rx_frame->preamble_start,
+ 0,
+ rx_frame->num_bytes+8,
+ COLOR_RED "Frame: ", "<---" COLOR_OFF );
+ return 0;
+ }
+
+ jsonType = ((json_start[0] << 24) |
+ (json_start[1] << 16) |
+ (json_start[2] << 8) |
+ (json_start[3] << 0));
+
+ switch (jsonType) {
+ case COPY_TYPE: {
+ uint32 length = ((unsigned int)rx_frame->num_bytes) - (json_start - &rx_frame->preamble_start[0]);
+ process_copy(json_start+4, length);
+ break;
+ } // case COPY_TYPE
+
+ case DNLD_TYPE: {
+ uint32 length = ((unsigned int)rx_frame->num_bytes) - (json_start - &rx_frame->preamble_start[0]);
+ process_dnld(json_start+4, length);
+ break;
+ } // case DNLD_TYPE
+
+ case JSON_TYPE:
+ process_json(rx_frame);
+ break;
+
+ // case 0x030050fe: /* 03:OAM 0050:FLAGS fe:OAMPDU */
+ default: {
+ uint8_t subtype = json_start[0];
+
+ switch (subtype) {
+
+ case slow_protocol_subtype_oam: {
+ uint16_t flags_expected = oam_flag_loc_stab | oam_flag_rem_stab; // 0x50;
+ uint16_t flags_actual = tb_unpack_u16(json_start+1);
+
+ if (flags_expected != flags_actual) {
+ TB_WARNING("unexpected flags 0x%04x actual vs. 0x%04x expected",
+ flags_actual, flags_expected);
+ rc = TB_RC_REMOTE_PEER_RESP;
+ } else {
+ uint8_t opcode = json_start[3];
+
+ switch (opcode) {
+ case oam_pdu_code_organization_specific: {
+
+ /* If the destination address for the OAM PDU was the OLT's
+ * ethernet port, then invoke the local OAM handling code. */
+ if ((!memcmp(dest_addr.u8, tbg.mac_0_address.u8, sizeof(mac_address))) &&
+ (vid == 0))
+ {
+ uint32 length = ((unsigned int)rx_frame->num_bytes) - (json_start - &rx_frame->preamble_start[0]);
+
+ if (0 == memcmp(json_start+4, dpoe_oui, 3)) {
+ TB_TRACE("dispatching to DPoE organization-specific handler");
+ rc = oam_hdl_org_spec_dpoe(&remote_addr, json_start+7, length-7);
+ } else if (0 == memcmp(json_start+4, tibit_oam_oui, 3)) {
+ TB_TRACE("dispatching to Tibit organization-specific handler");
+ rc = oam_hdl_org_spec_tibit(&remote_addr, json_start+7, length-7);
+ } else {
+ uint32 oui = tb_unpack_u24(json_start+4);
+ TB_ERROR("unknown organization-specific OUI %06x", oui);
+ rc = TB_RC_REMOTE_PEER_RESP;
+ }
+
+ } else if (olt_device_p()) {
+ /* Forward the OAM request */
+ if (vid != 0) {
+ /* Constructing the ONU MAC address from the VLAN value. For the board MAC
+ * address, all Tibit MAC addresses use the EPON identifier */
+ dest_addr.u8[3] = (unsigned char)(MANDATA_PON_TYPE_10G_EPON_ONU << 4)
+ | TB_IFC_TYPE_ONU;
+ dest_addr.u8[4] = (vid - VOLTHA_ONU_BASE_VLAN);
+ }
+ dest_addr.u8[0] = 0x00;
+ dest_addr.u8[1] = 0x25;
+ dest_addr.u8[2] = 0xdc;
+ dest_addr.u8[3] = 0xd9;
+
+ dest_addr.u8[5] = 0x10;
+
+ rc = cli_forward_oam(rx_frame, &dest_addr, &remote_addr, json_start, vid);
+ } else {
+ TB_ERROR("Can only forward OAM PDUs from an OLT");
+ rc = TB_RC_REMOTE_PEER_RESP;
+ }
+
+ break;
+ } // case 0xfe
+
+ default:
+ TB_ERROR("unknown opcode 0x%x", opcode);
+ rc = TB_RC_REMOTE_PEER_RESP;
+ break;
+ } // switch (opcode)
+ } // else
+
+ break;
+ } // case slow_protocol_subtype_oam
+
+ default:
+ TB_ERROR("unknown subtype 0x%02x", subtype);
+ rc = TB_RC_REMOTE_PEER_RESP;
+ break;
+ } // switch (subtype)
+
+ // uint32 length = ((unsigned int)rx_frame->num_bytes) - (json_start - &rx_frame->preamble_start[0]);
+ TB_TRACE("rx_frame->num_bytes %u json_offset %u", rx_frame->num_bytes, (json_start - &rx_frame->preamble_start[0]));
+
+ tb_dbug_hexdump_one_line(TB_DBUG_LVL_TRACE, __FUNCTION__, __LINE__,
+ rx_frame->preamble_start,
+ 0,
+ rx_frame->num_bytes+8,
+ "Frame: ", "<---");
+
+ const uint8_t *dpoe_org_spec_start = json_start;
+ uint32 dpoe_org_spec_length = ((unsigned int)rx_frame->num_bytes) - (json_start - &rx_frame->preamble_start[0]);
+
+ tb_dbug_hexdump_one_line(TB_DBUG_LVL_TRACE, __FUNCTION__, __LINE__, dpoe_org_spec_start, 0, dpoe_org_spec_length, "orgspec: ", "<---");
+ break;
+ } // default
+ } // switch (jsonType)
+
+ return rc;
+}
+
+static int dump(const char *js, jsmntok_t * t, size_t count, int indent)
+{
+ int i, j, k;
+ static int found_operation = 0;
+ static int found_location = 0;
+ static int found_value = 0;
+ static int found_llid = 0;
+ static int found_macblock = 0;
+ static int found_itype = 0;
+ static int found_iinst = 0;
+ static int found_mac = 0;
+ static int found_cir = 0;
+ static int found_eir = 0;
+ static int found_swr = 0;
+ static int found_cvid = 0;
+ static int found_svid = 0;
+ static int found_cmd = 0;
+ static int found_code = 0;
+ static int found_tpid = 0;
+ static int found_vid = 0;
+ static int found_mode = 0;
+ static int found_tag_mode = 0;
+
+ if (count == 0) {
+ return 0;
+ }
+ if (t->type == JSMN_PRIMITIVE) {
+ TB_TRACE("PRIMITIVE: ");
+ TB_TRACE("%.*s", t->end - t->start, js + t->start);
+ return 1;
+ } else if (t->type == JSMN_STRING) {
+ TB_INFO("STRING: ");
+ TB_INFO("'%.*s'", t->end - t->start, js + t->start);
+ /*--- "operation" command ------------------------------------------*/
+ if (found_operation == 1) {
+ TB_INFO(" ACTION: storing 'operation' string");
+ if (strncmp("code", js + t->start, t->end - t->start) == 0) {
+ TB_TRACE("skipping code!");
+ } else {
+ memset(operation, 0, SIZE_OF_OPERATION);
+ strncpy(operation, js + t->start, t->end - t->start);
+ }
+ found_operation = 0;
+ }
+ if (strncmp("operation", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'operation'");
+ found_operation = 1;
+ }
+ /*--- "location" command -------------------------------------------*/
+ if (found_location == 1) {
+ TB_INFO(" ACTION: storing 'location'");
+ memset(location, 0, SIZE_OF_ADDRESS);
+ strncpy(location, js + t->start, t->end - t->start);
+ found_location = 0;
+ }
+ if (strncmp("address", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'location'");
+ found_location = 1;
+ }
+ /*--- "value" ------------------------------------------------------*/
+ if (found_value == 1) {
+ TB_INFO(" ACTION: storing 'value'");
+ memset(value, 0, SIZE_OF_VALUE);
+ strncpy(value, js + t->start, t->end - t->start);
+ found_value = 0;
+ }
+ if (strncmp("value", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'value'");
+ found_value = 1;
+ }
+ /*--- "llid" -------------------------------------------------------*/
+ if (found_llid == 1) {
+ TB_INFO(" ACTION: storing 'llid'");
+ memset(llid, 0, SIZE_OF_LLID);
+ strncpy(llid, js + t->start, t->end - t->start);
+ found_llid = 0;
+ }
+ if (strncmp("llid", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'llid'");
+ found_llid = 1;
+ }
+ /*--- "macblock" ---------------------------------------------------*/
+ if (found_macblock == 1) {
+ TB_INFO(" ACTION: storing 'macblock'");
+ memset(macblock, 0, SIZE_OF_MACBLOCK);
+ strncpy(macblock, js + t->start, t->end - t->start);
+ found_macblock = 0;
+ }
+ if (strncmp("macblock", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'macblock'");
+ found_macblock = 1;
+ }
+ /*--- "itype" ---------------------------------------------------*/
+ if (found_itype == 1) {
+ TB_INFO(" ACTION: storing 'itype'");
+ strncpy(itype, js + t->start, t->end - t->start);
+ found_itype = 0;
+ }
+ if (strncmp("itype", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'itype'");
+ found_itype = 1;
+ }
+ /*--- "iinst" ---------------------------------------------------*/
+ if (found_iinst == 1) {
+ TB_INFO(" ACTION: storing 'iinst'");
+ strncpy(iinst, js + t->start, t->end - t->start);
+ found_iinst = 0;
+ }
+ if (strncmp("iinst", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'iinst'");
+ found_iinst = 1;
+ }
+ /*--- "swr" ---------------------------------------------------*/
+ if (found_swr == 1) {
+ TB_INFO(" ACTION: storing 'swr'");
+ strncpy(swr, js + t->start, t->end - t->start);
+ found_swr = 0;
+ }
+ if (strncmp("swr", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'swr'");
+ found_swr = 1;
+ }
+ /*--- "mac" --------------------------------------------------------*/
+ if (found_mac == 1) {
+ TB_INFO(" ACTION: storing 'mac'");
+ strncpy(mac, js + t->start, t->end - t->start);
+
+ if (sizeof(mac_addr) != tb_str_to_buf(mac_addr.u8, mac, sizeof(mac_addr))) {
+ TB_ERROR("failed to parse macid `%s'", mac);
+ }
+
+ found_mac = 0;
+ }
+ if (strncmp("mac", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'mac'");
+ found_mac = 1;
+ }
+ /*--- "macid" ------------------------------------------------------*/
+ if (found_mac == 1) {
+ TB_INFO(" ACTION: storing 'macid'");
+ strncpy(mac, js + t->start, t->end - t->start);
+
+ if (sizeof(mac_addr) != tb_str_to_buf(mac_addr.u8, mac, sizeof(mac_addr))) {
+ TB_ERROR("failed to parse macid `%s'", mac);
+ }
+
+ found_mac = 0;
+ }
+ if (strncmp("macid", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'macid'");
+ found_mac = 1;
+ }
+ /*--- "cir" ---------------------------------------------------*/
+ if (found_cir == 1) {
+ TB_INFO(" ACTION: storing 'cir'");
+ strncpy(cir, js + t->start, t->end - t->start);
+ found_cir = 0;
+ }
+ if (strncmp("cir", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'cir'");
+ found_cir = 1;
+ }
+ /*--- "eir" ---------------------------------------------------*/
+ if (found_eir == 1) {
+ TB_INFO(" ACTION: storing 'eir'");
+ strncpy(eir, js + t->start, t->end - t->start);
+ found_eir = 0;
+ }
+ if (strncmp("eir", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'eir'");
+ found_eir = 1;
+ }
+ /*--- "svid" ---------------------------------------------------*/
+ if (found_svid == 1) {
+ TB_INFO(" ACTION: storing 'svid'");
+ strncpy(svid, js + t->start, t->end - t->start);
+ found_svid = 0;
+ }
+ if (strncmp("svid", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'svid'");
+ found_svid = 1;
+ }
+ /*--- "cvid" ---------------------------------------------------*/
+ if (found_cvid == 1) {
+ TB_INFO(" ACTION: storing 'cvid'");
+ strncpy(cvid, js + t->start, t->end - t->start);
+ found_cvid = 0;
+ }
+ if (strncmp("cvid", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'cvid'");
+ found_cvid = 1;
+ }
+ /*--- "cmd" --------------------------------------------------------*/
+ if (found_cmd == 1) {
+ TB_INFO(" ACTION: storing 'cmd'");
+ strncpy(cmd, js + t->start, t->end - t->start);
+ found_cmd = 0;
+ }
+ if (strncmp("cmd", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'cmd'");
+ found_cmd = 1;
+ }
+ /*--- "code" -------------------------------------------------------*/
+ if (found_code == 1) {
+ TB_INFO(" ACTION: storing 'code'");
+ memset(code, 0, sizeof(CODE_STR_LEN));
+ strncpy(code, js + t->start, t->end - t->start);
+ found_code = 0;
+ }
+ if (strncmp("code", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'code'");
+ found_code = 1;
+ }
+ /*--- "tpid" -------------------------------------------------------*/
+ if (found_tpid == 1) {
+ TB_INFO(" ACTION: storing 'tpid'");
+ memset(tpid, 0, sizeof(TPID_STR_LEN));
+ strncpy(tpid, js + t->start, t->end - t->start);
+ found_tpid = 0;
+ }
+ if (strncmp("tpid", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'tpid'");
+ found_tpid = 1;
+ }
+ /*--- "vid" --------------------------------------------------------*/
+ if (found_vid == 1) {
+ TB_INFO(" ACTION: storing 'vid'");
+ memset(vid, 0, sizeof(VID_STR_LEN));
+ strncpy(vid, js + t->start, t->end - t->start);
+ found_vid = 0;
+ }
+ if (strncmp("vid", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'vid'");
+ found_vid = 1;
+ }
+ /*--- "mode" --------------------------------------------------------*/
+ if (found_mode == 1) {
+ TB_INFO(" ACTION: storing 'mode'");
+ memset(mode, 0, sizeof(MODE_STR_LEN));
+ strncpy(mode, js + t->start, t->end - t->start);
+ found_mode = 0;
+ }
+ if (strncmp("mode", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'mode'");
+ found_mode = 1;
+ }
+ /*--- "mode" --------------------------------------------------------*/
+ if (found_tag_mode == 1) {
+ TB_INFO(" ACTION: storing 'tag_mode'");
+ memset(tag_mode, 0, sizeof(TAG_MODE_STR_LEN));
+ strncpy(tag_mode, js + t->start, t->end - t->start);
+ found_tag_mode = 0;
+ }
+ if (strncmp("tag_mode", js + t->start, t->end - t->start) == 0) {
+ TB_INFO(" ACTION: found 'tag_mode'");
+ found_tag_mode = 1;
+ }
+ return 1;
+ } else if (t->type == JSMN_OBJECT) {
+ TB_INFO("OBJECT: ");
+ TB_INFO("\n");
+ j = 0;
+ for (i = 0; i < t->size; i++) {
+ for (k = 0; k < indent; k++)
+ TB_INFO(" ");
+ /* tb_printf("--- dump one --- [j=%d] [count=%d, count - j = %d]\n", j, count, count-j); */
+ j += dump(js, t + 1 + j, count - j, indent + 1);
+ TB_INFO(": ");
+ if ((count - j - 1) > 0) {
+ /* tb_printf("--- dump two --- [j=%d] [count=%d, count - j = %d]\n", j, count, count-j); */
+ j += dump(js, t + 1 + j, count - j, indent + 1);
+ }
+ TB_INFO("\n");
+ }
+ return j + 1;
+ } else if (t->type == JSMN_ARRAY) {
+ TB_INFO("ARRAY: ");
+ j = 0;
+ TB_INFO("\n");
+ for (i = 0; i < t->size; i++) {
+ for (k = 0; k < indent - 1; k++)
+ TB_INFO(" ");
+ TB_INFO(" - ");
+ j += dump(js, t + 1 + j, count - j, indent + 1);
+ TB_INFO("\n");
+ }
+ return j + 1;
+ }
+ return 0;
+}
+
+static int json_version(tb_pkt_deprec_t * rx_frame)
+{
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ brdg_mem_t brdg_memory;
+ tb_mac_address_str_t mac_str;
+ brdg_return_t rc;
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ sprintf(tmp_string, "{\"operation\": \"version\", \"success\": true, \"results\": {");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ /* get bridge memory values */
+ brdg_mem_t_init(&brdg_memory);
+ brdg_memory.addr = 0x10000000;
+ brdg_memory.num = 3;
+ rc = brdg_mem_read(&brdg_memory);
+
+ if (rc != BRDG_RET_OK) {
+ json_error(rx_frame, rc);
+ }
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"manufacturer\": \"%08x\",", brdg_memory.data[0]);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ switch (tbg.PON) {
+ case MANDATA_PON_TYPE_10G_EPON_ONU:
+ sprintf(tmp_string, "\"device\": \"10G EPON ONU\",");
+ break;
+ case MANDATA_PON_TYPE_10G_EPON_OLT:
+ sprintf(tmp_string, "\"device\": \"10G EPON OLT\",");
+ break;
+ case MANDATA_PON_TYPE_10G_GPON_ONU:
+ sprintf(tmp_string, "\"device\": \"10G GPON ONT\",");
+ break;
+ case MANDATA_PON_TYPE_10G_GPON_OLT:
+ sprintf(tmp_string, "\"device\": \"10G GPON OLT\",");
+ break;
+ case MANDATA_PON_TYPE_1G_P2P:
+ case MANDATA_PON_TYPE_10G_P2P:
+ sprintf(tmp_string, "\"device\": \"10G/1G LAN\",");
+ break;
+ case MANDATA_PON_TYPE_1G_EPON_ONU:
+ case MANDATA_PON_TYPE_1G_GPON_ONU:
+ case MANDATA_PON_TYPE_1G_GPON_OLT:
+ case MANDATA_PON_TYPE_1G_EPON_OLT:
+ sprintf(tmp_string, "\"device\": \"1G PON DEVICE\",");
+ break;
+ default:
+ case MANDATA_PON_TYPE_UNK:
+ sprintf(tmp_string, "\"device\": \"UNK\",");
+ break;
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"datecode\": \"%08x\",", brdg_memory.data[2]);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"firmware\": \"%02d:%02d:%02d\",", __VERSION_MAJOR__, __VERSION_MINOR__,
+ __VERSION_REVISION__);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"modelversion\": \"%s\",", "1.0");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"macid\": \"%s\"", tb_mac_address_to_str(tbg.mac_0_address.u8, mac_str));
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}, ");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"error\": null");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+ return 0;
+}
+
+static int json_interfaces(tb_pkt_deprec_t * rx_frame)
+{
+ int i;
+ uint8_t max_count = 5;
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ tb_ifc_key_t olt_ifc_keys[JSON_MAX_INTERFACES];
+ tb_ifc_key_t onu_ifc_keys[JSON_MAX_INTERFACES];
+ tb_ifc_key_t eth_ifc_keys[JSON_MAX_INTERFACES];
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"interfaces\", \"success\": true, \"results\":[");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ if (onu_device_p()) {
+ onu_fsm_report_all_ifc_keys(&max_count, onu_ifc_keys);
+ if (max_count < JSON_MAX_INTERFACES) {
+ for (i = 0; i < max_count; i++) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"iinst\": \"%d\", \"itype\": \"onu\"}, ",
+ onu_ifc_keys[i].inst);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+ }
+ } else {
+ TB_TRACE("E:Num ifcs > size of table (%s:%d)", __FUNCTION__, __LINE__);
+ }
+ }
+
+ if (olt_device_p()) {
+ olt_fsm_report_all_ifc_keys(&max_count, olt_ifc_keys);
+ if (max_count < JSON_MAX_INTERFACES) {
+ for (i = 0; i < max_count; i++) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"iinst\": \"%d\", \"itype\": \"olt\"}, ",
+ olt_ifc_keys[i].inst);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+ }
+ } else {
+ TB_TRACE("E:Num ifcs > size of table (%s:%d)", __FUNCTION__, __LINE__);
+ }
+ }
+
+ eth_fsm_report_all_ifc_keys(&max_count, eth_ifc_keys);
+ if (max_count < JSON_MAX_INTERFACES) {
+ for (i = 0; i < max_count; i++) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"iinst\": \"%d\", \"itype\": \"eth\"}", eth_ifc_keys[i].inst);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+ }
+ } else {
+ TB_TRACE("E:Num ifcs > size of table (%s:%d)", __FUNCTION__, __LINE__);
+ }
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "],\"error\":null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return 0;
+} /* json_interfaces */
+
+#define MAX_REGISTERED_LINKS 16 /* for now... */
+static int json_links(tb_pkt_deprec_t * rx_frame, UNUSED_ARG char *itype, UNUSED_ARG tb_ifc_inst_t iinst)
+{
+ int i;
+ tb_mac_address_str_t mac_str = "";
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ mac_address all_zeros_mac = {.u8 = {0x00, 0x00, 0x00, 0x00, 0x00, 0x00} };
+ int num_links = 0;
+
+ mac_address registered_mac_addresses[MAX_REGISTERED_LINKS];
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ num_links = lsm_report_all_links_mgmt(registered_mac_addresses);
+
+ if (num_links >= MAX_REGISTERED_LINKS) {
+ TB_ERROR("Out of bounds error, more links than memory allocated");
+ } else if (num_links < 0) {
+ /* error condition */
+ TB_TRACE("I: (%s:%d)", __FUNCTION__, __LINE__);
+ }
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"links\", ");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ if (num_links) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"success\": true, \"results\":[");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ for (i = 0; i < num_links; i++) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ tb_mac_address_to_str(registered_mac_addresses[i].u8, mac_str);
+ if (i + 1 == num_links) {
+ sprintf(tmp_string, "{\"macid\": \"%s\"}", mac_str);
+ } else {
+ sprintf(tmp_string, "{\"macid\": \"%s\"},", mac_str);
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+ }
+ } else {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"success\": true, \"results\":[");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ tb_mac_address_to_str(all_zeros_mac.u8, mac_str);
+ /* sprintf(tmp_string, "{\"macid\": \"%s\"}", mac_str); */
+ /* json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame); */
+ }
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return 0;
+} /* json_links */
+
+static int json_register_read(tb_pkt_deprec_t * rx_frame, unsigned int address)
+{
+ brdg_mem_t brdg_memory;
+ brdg_return_t rc = BRDG_RET_OK;
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"register_read\", \"success\": true, \"results\": {");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+
+ brdg_mem_t_init(&brdg_memory);
+ brdg_memory.addr = address;
+ brdg_memory.num = 1;
+ rc = brdg_mem_read(&brdg_memory);
+
+ sprintf(tmp_string, "\"value\": \"%08x\"", brdg_memory.data[0]);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}, ");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"error\": null");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return rc;
+}
+
+static int json_register_write(tb_pkt_deprec_t * rx_frame, unsigned int address, unsigned int value)
+{
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ brdg_mem_t brdg_memory;
+ brdg_return_t rc = BRDG_RET_OK;
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ brdg_mem_t_init(&brdg_memory);
+ brdg_memory.addr = address;
+ brdg_memory.num = 1;
+ brdg_memory.data[0] = value;
+ rc = brdg_mem_write(&brdg_memory);
+
+ if (rc == BRDG_RET_OK) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string,
+ "{\"operation\": \"register_write\", \"success\": true, \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+ } else {
+ json_error(rx_frame, rc);
+ }
+
+ return rc;
+
+} /* json_register_write */
+
+static int json_stats(tb_pkt_deprec_t * rx_frame, unsigned int lidx, brdg_mac_block_t mac_block)
+{
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ unsigned long long int wide_total = 0;
+ brdg_return_t rc = BRDG_RET_OK;
+ brdg_dpram_t output;
+ brdg_dpram_t *p_out;
+ unsigned int s;
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ p_out = &output;
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"stats\", \"success\": true, \"results\":{");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ for (s = 0; s < 31; s++) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ p_out->num = 1;
+ if (lidx == 256) {
+ rc = (mac_block == MB0) ? brdg_dpram_read(SLCT_MSTAT_RDCLR_0, (s << 5) | 31,
+ p_out) : brdg_dpram_read(SLCT_MSTAT_RDCLR_1,
+ (s << 5) | 31,
+ p_out);
+ } else {
+ rc = (mac_block == MB0) ? brdg_dpram_read(SLCT_MSTAT_RDCLR_0, (lidx << 5) | s,
+ p_out) : brdg_dpram_read(SLCT_MSTAT_RDCLR_1,
+ (lidx << 5) | s,
+ p_out);
+ }
+ if (rc == BRDG_RET_OK) {
+ sprintf(tmp_string, "\"%s\":\"%u\", ", brdg_stat_name_lower[s], p_out->data[0]);
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+ }
+
+ for (s = 0; s < 7; s++) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ p_out->num = 2;
+ if (lidx == 256) {
+ rc = (mac_block == MB0) ? brdg_dpram_read(SLCT_MWIDE_RDCLR_0, (s << 3) | 7,
+ p_out) : brdg_dpram_read(SLCT_MWIDE_RDCLR_1,
+ (s << 3) | 7, p_out);
+ } else {
+ rc = (mac_block == MB0) ? brdg_dpram_read(SLCT_MWIDE_RDCLR_0, (lidx << 3) | s,
+ p_out) : brdg_dpram_read(SLCT_MWIDE_RDCLR_1,
+ (lidx << 3) | s,
+ p_out);
+ }
+ if (rc == BRDG_RET_OK) {
+ wide_total = p_out->data[1];
+ wide_total <<= 32ULL;
+ wide_total += p_out->data[0];
+ if (s != 6) { /* ! last one */
+ sprintf(tmp_string, "\"%s\":\"%llu\", ", brdg_stat_total_lower[s], wide_total);
+ } else {
+ sprintf(tmp_string, "\"%s\":\"%llu\"", brdg_stat_total_lower[s], wide_total);
+ }
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+ }
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}, ");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"error\": null");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return rc;
+}
+
+static int json_error(tb_pkt_deprec_t * rx_frame, brdg_return_t brdg_return_code)
+{
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"%s\", \"success\": false, \"results\": {}, ", operation);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ switch (brdg_return_code) {
+ case BRDG_RET_INPUT_INVALID:
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"error\": {\"code\": 2, \"message\": \"Missing parameters\"");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+ break;
+ default:
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"error\": {\"code\": 5, \"message\": \"Unknown error\"");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ break;
+ }
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return 0;
+}
+
+static int json_str_append_and_out(char *global_json_string, char *tmp_string,
+ json_string_print_t output, tb_pkt_deprec_t * rx_frame)
+{
+ uint i;
+ static int offset = 0;
+ mac_address tmp_mac;
+
+ if (output != RESET) {
+ TB_TRACE("jstr: @pos[%d] + %d chars", offset, (int)strlen(tmp_string));
+ strncpy(global_json_string + offset, tmp_string, strlen(tmp_string));
+ offset += strlen(tmp_string);
+ }
+
+ switch (output) {
+ case RESET:
+ offset = 0;
+ break;
+
+ case APPEND_AND_FLUSH:
+ offset = 0;
+ TB_TRACE("%s", global_json_string);
+ break;
+
+ case APPEND_AND_FLUSH_CR:
+ if (command_line_json) {
+ tb_printf("%s\n", global_json_string);
+ command_line_json = false;
+ } else {
+ TB_TRACE("%s", global_json_string);
+ }
+ /* store src address in tmp */
+ memcpy(tmp_mac.u8, &rx_frame->preamble_start[14], sizeof(mac_address));
+ /* make src my mac */
+ memcpy(&rx_frame->preamble_start[14], tbg.mac_0_address.u8, sizeof(mac_address));
+ /* make tmp src new dst */
+ memcpy(&rx_frame->preamble_start[8], tmp_mac.u8, sizeof(mac_address));
+ if (tbg.mgmt_vlan != MGMT_VLAN_DISABLED) {
+ /* VLAN HEADER: */
+ rx_frame->preamble_start[20] = tbg.outer_tpid >> 8;
+ rx_frame->preamble_start[21] = tbg.outer_tpid & 0xff;
+ rx_frame->preamble_start[22] = (MGMT_VLAN_PRIORITY << 5) | (tbg.mgmt_vlan >> 8);
+ rx_frame->preamble_start[23] = tbg.mgmt_vlan & 0xff;
+ rx_frame->preamble_start[24] = 0x90;
+ rx_frame->preamble_start[25] = 0x01;
+ rx_frame->preamble_start[26] = 0x6a; /* j */
+ rx_frame->preamble_start[27] = 0x73; /* s */
+ rx_frame->preamble_start[28] = 0x6f; /* o */
+ rx_frame->preamble_start[29] = 0x6e; /* n */
+ rx_frame->preamble_start[30] = 0x20; /* 'space' */
+ /* FIX: Magic numbers +4 for VLAN, START_OF_JSON_VLAN header, offset = payload, 4 for CRC */
+ rx_frame->num_bytes = 4 + START_OF_JSON_VLAN + offset;
+ TB_TRACE("num_bytes %d", rx_frame->num_bytes);
+ memcpy(&rx_frame->preamble_start[START_OF_JSON_VLAN], global_json_string, rx_frame->num_bytes);
+ } else {
+ /* FIX: Magic numbers START_OF_JSON_UNTAGGED header, offset = payload, 4 for CRC */
+ rx_frame->num_bytes = START_OF_JSON_UNTAGGED + offset + 4;
+ memcpy(&rx_frame->preamble_start[START_OF_JSON_UNTAGGED], global_json_string, rx_frame->num_bytes);
+ }
+ for (i = 0; i < rx_frame->num_bytes; ++i) {
+ uint16_t dword_idx = i / 4;
+ uint8_t byte_shift = (3 - (i % 4)) << 3; // 0->24, 1->16, 2->8, 3->0
+
+ // i 3-(i%4) byte_shift
+ // --------------------------
+ // 0 3 24
+ // 1 2 16
+ // 2 1 8
+ // 3 0 0
+ // 4 3 24
+ // 5 2 16
+ // 6 1 8
+ // â‹® â‹® â‹®
+ if (0 == (i % 4)) {
+ rx_frame->data[dword_idx] = 0;
+ }
+ rx_frame->data[dword_idx] |= (rx_frame->preamble_start[i] << byte_shift);
+ }
+
+ rx_frame->tx_modifier = BRDG_MODIFIER_FLAG_APPLY_CRC;
+
+ brdg_que_write(7, BRDG_MODIFIER_FLAG_APPLY_CRC, rx_frame);
+
+ offset = 0;
+ break;
+ case APPEND:
+ default:
+ /* do nothing */
+ break;
+ }
+
+ return 0;
+}
+
+static tb_rc json_fec_set(tb_pkt_deprec_t * rx_frame, tb_ifc_key_t * ifc_key, bool fec_enabled)
+{
+ tb_rc rc = TB_RC_OK;
+
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string,
+ "{\"operation\": \"fec_set\", \"success\": true, \"results\": [], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ olt_fsm_fec_enable_set(ifc_key, fec_enabled, fec_enabled);
+
+ return rc;
+}
+
+static tb_rc json_fec_get(tb_pkt_deprec_t * rx_frame, tb_ifc_key_t * ifc_key)
+{
+ tb_rc rc = TB_RC_OK;
+ bool fec_tx_enable = false;
+ bool fec_rx_enable = false;
+
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"fec_get\", \"success\": true, \"results\": ");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ rc = olt_fsm_fec_enable_get(ifc_key, &fec_tx_enable, &fec_rx_enable);
+
+ if (fec_tx_enable == true) {
+ sprintf(tmp_string, "{\"mode\": \"enabled\"}");
+ } else {
+ sprintf(tmp_string, "{\"mode\": \"disabled\"}");
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, ", \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return rc;
+}
+
+static tb_rc json_tag_mode_set(tb_pkt_deprec_t * rx_frame, char * tag_mode)
+{
+ tb_rc rc = TB_RC_OK;
+
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string,
+ "{\"operation\": \"tag_mode_set\", \"success\": true, \"results\": [], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ if (strncmp(tag_mode, "SC", 3) == 0) {
+ rc = hwsys_manufacturing_CTAG_CTAG_write(false);
+ } else {
+ rc = hwsys_manufacturing_CTAG_CTAG_write(true);
+ }
+
+ return rc;
+}
+
+static tb_rc json_tag_mode_get(tb_pkt_deprec_t * rx_frame)
+{
+ tb_rc rc = TB_RC_OK;
+
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"tag_mode_get\", \"success\": true, \"results\": ");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+
+ if (tbg.outer_tpid == 0x8100) {
+ sprintf(tmp_string, "{\"tag_mode\": \"CC\"}");
+ } else {
+ sprintf(tmp_string, "{\"tag_mode\": \"SC\"}");
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, ", \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return rc;
+}
+
+static tb_rc json_sla_set(tb_pkt_deprec_t * rx_frame, lsm_link_key_t * link_key,
+ lsm_link_sla_spec_t * sla_spec)
+{
+ tb_rc rc = lsm_link_sla_set(link_key, sla_spec);
+
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string,
+ "{\"operation\": \"sla_set\", \"success\": true, \"results\": [], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return rc;
+}
+
+static tb_rc json_sla_get(tb_pkt_deprec_t * rx_frame, lsm_link_key_t * link_key,
+ lsm_link_sla_spec_t * sla_spec)
+{
+ tb_rc rc = lsm_link_sla_get(link_key, sla_spec);
+
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"sla_get\", \"success\": true, \"results\": [");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"cir\": \"%u\", \"eir\": \"%u\"}", (unsigned int)sla_spec->cir_Kbps,
+ (unsigned int)sla_spec->eir_Kbps);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return rc;
+}
+
+static tb_rc json_flows_add(tb_pkt_deprec_t * rx_frame, tb_ifc_key_t * ifc_key,
+ sw_rec_key_t * sw_rec_key, port_vlan_op_cfg_t port_vlan_op_cfg)
+{
+ tb_rc rc = TB_RC_OK;
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+
+ rc = sw_associate_port(sw_rec_key, ifc_key, port_vlan_op_cfg);
+ if (rc != TB_RC_OK) {
+ TB_INFO("%s:%d Failed sw_associate.", __FUNCTION__, __LINE__);
+ }
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ if ((rc == TB_RC_OK) || (rc == TB_RC_ALREADY)) {
+ sprintf(tmp_string, "{\"operation\": \"flows_add\", \"success\": true, \"results\": [");
+ } else {
+ sprintf(tmp_string, "{\"operation\": \"flows_add\", \"success\": false, \"results\": [");
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return rc;
+}
+
+static tb_rc json_flows_delete(tb_pkt_deprec_t * rx_frame, tb_ifc_key_t * ifc_key,
+ sw_rec_key_t * sw_rec_key)
+{
+ tb_rc rc = TB_RC_OK;
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+
+ rc = sw_dissociate_port(sw_rec_key, ifc_key);
+ if (rc != TB_RC_OK) {
+ tb_printf("%s:%d Failed sw_deassociate. (rc=%d)\n", __FUNCTION__, __LINE__, rc);
+ }
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ if ((rc == TB_RC_OK) || (rc == TB_RC_ALREADY)) {
+ sprintf(tmp_string, "{\"operation\": \"flows_delete\", \"success\": true, \"results\": [");
+ } else {
+ sprintf(tmp_string, "{\"operation\": \"flows_delete\", \"success\": false, \"results\": [");
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return rc;
+}
+
+#define MAX_SWITCHING_RECORDS 20 /* for now... */
+static tb_rc json_flows_get(tb_pkt_deprec_t * rx_frame)
+{
+ tb_rc rc = TB_RC_OK;
+ int i, j = 0;
+ int num_switching_records = 0;
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ sw_rec_key_t switching_record[MAX_SWITCHING_RECORDS];
+ tb_port_key_t ports_per_record[MAX_SWITCHING_RECORDS][MAX_REPORTABLE_PORTS_PER_SW_RECORD];
+ tb_mac_address_str_t mac_str = "";
+
+ memset(switching_record, 0, sizeof(sw_rec_key_t) * MAX_SWITCHING_RECORDS);
+ memset(ports_per_record, 0,
+ sizeof(tb_port_key_t) * MAX_SWITCHING_RECORDS * MAX_REPORTABLE_PORTS_PER_SW_RECORD);
+
+ num_switching_records =
+ sw_report_all_sw_rec_mgmt(MAX_SWITCHING_RECORDS, switching_record,
+ MAX_REPORTABLE_PORTS_PER_SW_RECORD, ports_per_record);
+
+ if (num_switching_records >= MAX_SWITCHING_RECORDS) {
+ TB_ERROR("Out of bounds error, more swr than memory allocated");
+ } else if (num_switching_records < 0) {
+ TB_TRACE("I: (%s:%d)", __FUNCTION__, __LINE__);
+ return (rc = TB_RC_INTERNAL_ERROR);
+ }
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ if (num_switching_records) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ if ((rc == TB_RC_OK) || (rc == TB_RC_ALREADY)) {
+ sprintf(tmp_string, "{\"operation\": \"flows\", \"success\": true, \"results\": [");
+ } else {
+ sprintf(tmp_string, "{\"operation\": \"flows\", \"success\": false, \"results\": [");
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ for (i = 0; i < num_switching_records; i++) {
+ if (i >= 1) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, ",");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+ }
+ for (j = 0; j < MAX_REPORTABLE_PORTS_PER_SW_RECORD; j++) {
+ tb_port_type_t type = ports_per_record[i][j].port_type;
+ /* printf("MGMT_JSON[%d][%d]: port type %u\n", i, j, type); */
+ if (type && (j >= 1)) {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, ",");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+ }
+
+ switch (type) {
+ case tb_port_type_eth_dn: {
+ tb_ifc_key_t *ifc_key = &ports_per_record[i][j].key.ifc;
+ lsm_link_key_t link_key;
+ port_vlan_op_cfg_t port_vlan_op_cfg;
+ port_vlan_op_cfg_t *p_vlan_op_cfg;
+
+ /* ingress switch record */
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"ingress_switch_record\": {\"svid\": \"%05d\", \"cvid\": \"%05d\"},",
+ switching_record[i].outer_vid, switching_record[i].inner_vid);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ /* ingress port */
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"ingress_port\": {\"iinst\": \"%d\", \"itype\": \"eth\"},",
+ ifc_key->inst);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ /* egress port */
+ rc = hal_find_link_key_by_llid(switching_record[i].default_dest, &link_key);
+ if (rc != TB_RC_OK) {
+ TB_ERROR("find link key failed");
+ }
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ tb_mac_address_to_str(link_key.mac.u8, mac_str);
+ sprintf(tmp_string, "\"egress_port\": {\"iinst\": \"%d\", \"itype\": \"olt\", \"macid\": \"%s\"},",
+ link_key.ifc_inst, mac_str);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ /* vlan operation */
+ memset(&port_vlan_op_cfg, 0, sizeof(port_vlan_op_cfg));
+
+ p_vlan_op_cfg = sw_find_port_vlan_op_cfg(&switching_record[i],
+ &ports_per_record[i][0], /* single ports right now */
+ &port_vlan_op_cfg);
+
+ if (p_vlan_op_cfg == NULL) {
+ TB_ERROR("p_vlan_op_cfg is NULL");
+ }
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ if ((port_vlan_op_cfg[0].op_type != port_vlan_op_type_unspecified) &&
+ (port_vlan_op_cfg[0].op_type != port_vlan_op_type_none)) {
+ /* STAG */
+ sprintf(tmp_string, "\"operation\": ");
+ switch (port_vlan_op_cfg[0].op_type) {
+ case port_vlan_op_type_push:
+ sprintf(tmp_string + 13, "{\"code\": \"push\", \"tpid\": \"88a8\", \"vid\": \"%d\"}",
+ port_vlan_op_cfg[0].op_arg);
+ break;
+ case port_vlan_op_type_pop:
+ sprintf(tmp_string + 13, "{\"code\": \"pop\", \"tpid\": \"88a8\"}");
+ break;
+ case port_vlan_op_type_none:
+ sprintf(tmp_string + 13, "{\"code\": \"none\", \"tpid\": \"88a8\"}");
+ break;
+ default:
+ case port_vlan_op_type_translate:
+ case port_vlan_op_type_count:
+ case port_vlan_op_type_unspecified:
+ TB_TRACE("stag unspecified");
+ break;
+ }
+ } else if ((port_vlan_op_cfg[1].op_type != port_vlan_op_type_unspecified) &&
+ (port_vlan_op_cfg[0].op_type != port_vlan_op_type_none)) {
+ /* CTAG */
+ sprintf(tmp_string, "\"operation\": ");
+ switch (port_vlan_op_cfg[1].op_type) {
+ case port_vlan_op_type_push:
+ sprintf(tmp_string + 13, "{\"code\": \"push\", \"tpid\": \"8100\", \"vid\": \"%d\"}",
+ port_vlan_op_cfg[1].op_arg);
+ break;
+ case port_vlan_op_type_pop:
+ sprintf(tmp_string + 13, "{\"code\": \"pop\", \"tpid\": \"8100\"}");
+ break;
+ case port_vlan_op_type_none:
+ sprintf(tmp_string + 13, "{\"code\": \"none\", \"tpid\": \"8100\"}");
+ break;
+ default:
+ case port_vlan_op_type_translate:
+ case port_vlan_op_type_count:
+ case port_vlan_op_type_unspecified:
+ TB_TRACE("ctag unspecified");
+ break;
+ }
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ break;
+ }
+ case tb_port_type_llid_up: {
+ lsm_link_key_str_t link_key_str;
+ lsm_link_key_t *link_key = &ports_per_record[i][j].key.link;
+ tb_ifc_subinst_t llid = lsm_find_llid_by_link_key(link_key);
+ port_vlan_op_cfg_t port_vlan_op_cfg;
+ port_vlan_op_cfg_t *p_vlan_op_cfg;
+ lsm_link_key_llid_to_str(link_key, llid, link_key_str);
+
+ /* ingress switch record */
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"ingress_switch_record\": {\"svid\": \"%05d\", \"cvid\": \"%05d\"},",
+ switching_record[i].outer_vid, switching_record[i].inner_vid);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+
+ /* ingress port */
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ tb_mac_address_to_str(link_key->mac.u8, mac_str);
+ sprintf(tmp_string, "\"ingress_port\": {\"iinst\": \"%d\", \"itype\": \"olt\", \"macid\": \"%s\"},",
+ link_key->ifc_inst, mac_str);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ /* egress port */
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"egress_port\": {\"iinst\": \"0\", \"itype\": \"eth\"},");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ /* vlan operation */
+ memset(&port_vlan_op_cfg, 0, sizeof(port_vlan_op_cfg));
+ p_vlan_op_cfg = sw_find_port_vlan_op_cfg(&switching_record[i],
+ &ports_per_record[i][0], /* single ports right now */
+ &port_vlan_op_cfg);
+
+ if (p_vlan_op_cfg == NULL) {
+ TB_ERROR("p_vlan_op_cfg is NULL");
+ }
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ if (port_vlan_op_cfg[0].op_type != port_vlan_op_type_unspecified) {
+ /* STAG */
+ sprintf(tmp_string, "\"operation\": ");
+ switch (port_vlan_op_cfg[0].op_type) {
+ case port_vlan_op_type_push:
+ sprintf(tmp_string + 13, "{\"code\": \"push\", \"tpid\": \"88a8\", \"vid\": \"%d\"}",
+ port_vlan_op_cfg[0].op_arg);
+ break;
+ case port_vlan_op_type_pop:
+ sprintf(tmp_string + 13, "{\"code\": \"pop\", \"tpid\": \"88a8\"}");
+ break;
+ case port_vlan_op_type_none:
+ sprintf(tmp_string + 13, "{\"code\": \"none\", \"tpid\": \"88a8\"}");
+ break;
+ default:
+ case port_vlan_op_type_translate:
+ case port_vlan_op_type_count:
+ case port_vlan_op_type_unspecified:
+ break;
+ }
+ } else if (port_vlan_op_cfg[1].op_type != port_vlan_op_type_unspecified) {
+ /* CTAG */
+ sprintf(tmp_string, "\"operation\": ");
+ switch (port_vlan_op_cfg[1].op_type) {
+ case port_vlan_op_type_push:
+ sprintf(tmp_string + 13, "{\"code\": \"push\", \"tpid\": \"8100\", \"vid\": \"%d\"}",
+ port_vlan_op_cfg[1].op_arg);
+ break;
+ case port_vlan_op_type_pop:
+ sprintf(tmp_string + 13, "{\"code\": \"pop\", \"tpid\": \"8100\"}");
+ break;
+ case port_vlan_op_type_none:
+ sprintf(tmp_string + 13, "{\"code\": \"none\", \"tpid\": \"8100\"}");
+ break;
+ default:
+ case port_vlan_op_type_translate:
+ case port_vlan_op_type_count:
+ case port_vlan_op_type_unspecified:
+ break;
+ }
+ }
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+ break;
+ }
+ default:
+ rc = TB_RC_INTERNAL_ERROR;
+ break;
+ } // switch
+ }
+ }
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ } else {
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"flows\", \"success\": true, \"results\": [], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+ }
+
+ return rc;
+}
+
+static tb_rc json_mode_set(tb_pkt_deprec_t * rx_frame, mandata_pon_type_t PON)
+{
+ tb_rc rc = TB_RC_OK;
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+ unsigned int serial_number = 0;
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"mode_set\", \"success\": true, \"results\": [");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ sleep_ms(20);
+
+ /* Only change if we not currently at the requested mode */
+ if (tbg.PON != PON) {
+ rc = hwsys_manufacturing_pon_write(PON);
+ if (rc == 0) {
+ rc = hwsys_manufacturing_pon_read(&tbg.PON);
+ if (rc != 0) {
+ tb_printf("E: PON read error (%s:%d)\n", __FILE__, __LINE__);
+ }
+
+ /* if the PON type changes, re-write the mac addresses */
+ hwsys_manufacturing_serial_read(&serial_number);
+ set_sernum_and_mac_address(serial_number);
+
+ hw_reset(); /* RESET the BITSTREAM */
+ }
+ }
+ return rc;
+}
+
+static tb_rc json_cli_cmd(tb_pkt_deprec_t * rx_frame)
+{
+ tb_rc rc = TB_RC_OK;
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "{\"operation\": \"cli\", \"success\": true, \"results\": [");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "], \"error\": null}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+
+ return rc;
+}
+
+typedef struct {
+ uint32 image_length;
+ uint32 crc32_expected;
+ uint32 crc32_actual;
+} image_header_t;
+
+// [tibit@tibit-ubuntu-vm-pow] /opt/tbos.git $ cat /tmp/hello.txt
+// hello, world!
+// [tibit@tibit-ubuntu-vm-pow] /opt/tbos.git $ od -t x1 /tmp/hello.txt
+// 0000000 68 65 6c 6c 6f 2c 20 77 6f 72 6c 64 21 0a
+// [tibit@tibit-ubuntu-vm-pow] /opt/tbos.git $ crc32 /tmp/hello.txt
+// b631dfc0
+// [tibit@tibit-ubuntu-vm-pow] /opt/tbos.git $ wc -c /tmp/hello.txt
+// 14 /tmp/hello.txt
+
+static int process_copy(const uint8_t *msg_buf, UNUSED_ARG uint32 msg_len)
+{
+ const uint8_t *image_start = (const uint8_t *)0x81000000;
+ const uint8_t *image_length_packed = msg_buf;
+ const uint8_t *crc32_expected_packed = msg_buf + 4;
+ uint32 crc32_expected = tb_unpack_u32(crc32_expected_packed);
+ uint32 image_length = tb_unpack_u32(image_length_packed);
+ uint32 crc32_actual = crc32(image_start, image_length);
+
+ TB_WARNING("[copy] image_length %u crc32_expected 0x%08x crc32_actual 0x%08x", image_length, crc32_expected, crc32_actual);
+ if (crc32_expected == crc32_actual) {
+ image_header_t *header = (image_header_t *)(image_start - sizeof(image_header_t));
+
+ TB_WARNING("-> writing image header");
+ header->image_length = image_length;
+ header->crc32_expected = crc32_expected;
+ header->crc32_actual = 0; // calculated & compared w/ expected value by U-Boot script
+
+ tb_dbug_hexdump_one_line(TB_DBUG_LVL_WARNING, __FUNCTION__, __LINE__, header, 0, 32, "header+image: ", " ...");
+ } else {
+ TB_ERROR("crc32_expected 0x%08x != crc32_actual 0x%08x", crc32_expected, crc32_actual);
+ }
+
+ return 0;
+}
+
+static int process_dnld(const uint8_t *msg_buf, uint32 msg_len)
+{
+ const uint8_t *start_offset_packed = msg_buf;
+ const uint8_t *fragment_length_packed = msg_buf + 4;
+ const uint8_t *fragment_start = msg_buf + 8;
+ uint32 start_offset = tb_unpack_u32(start_offset_packed);
+ uint32 fragment_length = tb_unpack_u32(fragment_length_packed);
+ uint8_t *dest_buf = (uint8_t *)0x81000000;
+
+ TB_WARNING("[dnld] memcpy(%p, %p, %u)", dest_buf+start_offset, fragment_start, fragment_length);
+ tb_dbug_hexdump_one_line(TB_DBUG_LVL_WARNING, __FUNCTION__, __LINE__, msg_buf, 0, msg_len, "msg_buf: ", NULL);
+ tb_dbug_hexdump_one_line(TB_DBUG_LVL_WARNING, __FUNCTION__, __LINE__, fragment_start, 0, fragment_length, "fragment: ", NULL);
+ memcpy(dest_buf+start_offset, fragment_start, fragment_length);
+
+ return 0;
+}
+
+int json_send_response(char *type, char *buffer, uint16_t bufflen)
+{
+ tb_pkt_deprec_t *rx_frame = &fake_frame;
+ char tmp_string[SIZE_OF_TMP_STRING] = { '\0' };
+
+ memset(rx_frame, 0, sizeof(*rx_frame));
+
+ memset(global_json_string, 0, SIZE_OF_JSON_STRING);
+ json_str_append_and_out(global_json_string, tmp_string, RESET, rx_frame);
+
+ // Add the header
+ sprintf(tmp_string, "{\"operation\": \"%s\", \"success\": true, \"results\": {", type);
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ if (bufflen > SIZE_OF_JSON_STRING) {
+ json_error(rx_frame, BRDG_RET_NOT_OK);
+ return 0;
+ }
+
+ // Add the attribute values
+ json_str_append_and_out(global_json_string, buffer, APPEND, rx_frame);
+
+ // Add the trailer
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}, ");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "\"error\": null");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND, rx_frame);
+
+ memset(tmp_string, 0, SIZE_OF_TMP_STRING);
+ sprintf(tmp_string, "}");
+ json_str_append_and_out(global_json_string, tmp_string, APPEND_AND_FLUSH_CR, rx_frame);
+ return 0;
+}
+
+
+
+static int process_json(tb_pkt_deprec_t * rx_frame)
+{
+ int r;
+ int eof_expected = 0;
+ char *js = NULL;
+ size_t jslen = 0;
+ char buf[TB_PKT_DEPREC_PAYLOAD_BYTES];
+ jsmn_parser p;
+ jsmntok_t *tok;
+ size_t tokcount = 2;
+ unsigned int json_length = 0;
+
+ jsmn_init(&p);
+
+ /* Allocate some tokens as a start */
+ tok = malloc(sizeof(*tok) * tokcount);
+ if (tok == NULL) {
+ printf("malloc(): errno=%d\n", errno);
+ return 3;
+ }
+
+ memset(buf, 0, sizeof(buf));
+#ifdef USE_VLAN_HEADER_INCOMING
+ json_length = (rx_frame->num_bytes - START_OF_JSON_VLAN - FRAME_CRC_SIZE);
+ strncpy(buf, (const char *)&rx_frame->preamble_start[START_OF_JSON_VLAN], json_length);
+#else
+ json_length = (rx_frame->num_bytes - START_OF_JSON_UNTAGGED - FRAME_CRC_SIZE);
+ strncpy(buf, (const char *)&rx_frame->preamble_start[START_OF_JSON_UNTAGGED], json_length);
+#endif
+ r = strlen(buf);
+ /* tb_printf("STRLEN:[%d] %s\n", r, buf); */
+
+ if (r <= 0) {
+ if (tok != NULL) { free(tok); }
+ if (js != NULL) { free(js); }
+ if (r < 0) {
+ printf("fread(): %d, errno=%d\n", r, errno);
+ return 1;
+ }
+ if (r == 0) {
+ if (eof_expected != 0) {
+ return 0;
+ } else {
+ printf("fread(): unexpected EOF\n");
+ return 2;
+ }
+ }
+ }
+
+ js = realloc(js, jslen + r + 1);
+ if (js == NULL) {
+ printf("realloc(): errno=%d\n", errno);
+ if (tok != NULL) { free(tok); }
+ return 3;
+ }
+ strncpy(js + jslen, buf, r);
+ jslen = jslen + r;
+
+ again:
+ r = jsmn_parse(&p, js, jslen, tok, tokcount);
+ if (r < 0) {
+ if (r == JSMN_ERROR_NOMEM) {
+ tokcount = tokcount * 2;
+ tok = realloc(tok, sizeof(*tok) * tokcount);
+ if (tok == NULL) {
+ printf("realloc(): errno=%d\n", errno);
+ if (js != NULL) { free(js); }
+ return 3;
+ }
+ goto again;
+ }
+ } else {
+ /* This is the starting point for processing a JSON frame */
+ /* tb_printf("START_JSON_PARSE\n"); */
+ dump(js, tok, p.toknext, 0);
+ eof_expected = 1;
+ }
+
+ if (tok != NULL) { free(tok); }
+ if (js != NULL) { free(js); }
+
+ if (strlen(operation) != 0) {
+ if (strcmp(operation, "version") == 0) {
+ json_version(rx_frame);
+ } else if (strcmp(operation, "interfaces") == 0) {
+ json_interfaces(rx_frame);
+ } else if (strcmp(operation, "links") == 0) {
+ json_links(rx_frame, itype, strtoul(iinst, NULL, 10));
+ } else if (strcmp(operation, "register_read") == 0) {
+ if (strlen(location) == 0) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ json_register_read(rx_frame, strtoul(location, NULL, 16));
+ }
+ } else if (strcmp(operation, "register_write") == 0) {
+ if (strlen(location) == 0) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ json_register_write(rx_frame, strtoul(location, NULL, 16),
+ strtoul(value, NULL, 16));
+ }
+ } else if (strcmp(operation, "stats") == 0) {
+ if ((strlen(itype) == 0) || (strlen(iinst) == 0) || (strlen(mac) == 0)) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ uint16_t lidx = 0;
+ /* tb_ifc_key_t ifc_key = { .type = TB_IFC_TYPE_OLT, */
+ /* .inst = strtoul(iinst,NULL,10) }; */
+ lsm_link_key_t link_key = {.ifc_type = TB_IFC_TYPE_OLT,
+ .ifc_inst = strtoul(iinst, NULL, 10)
+ };
+ /* hal_ifc_hw_cfg *hw_cfg; */
+
+ if (0 == strcmp("olt", itype)) {
+ /* ifc_key.type = TB_IFC_TYPE_OLT; */
+ link_key.ifc_type = TB_IFC_TYPE_OLT;
+ if (gpon_device_p()) {
+ link_key.ifc_type = TB_IFC_TYPE_ALLOC_ID;
+ }
+ } else if (0 == strcmp("onu", itype)) {
+ /* ifc_key.type = TB_IFC_TYPE_ONU; */
+ link_key.ifc_type = TB_IFC_TYPE_ONU;
+ }
+ /* hw_cfg = hal_get_hw_cfg_by_key(ifc_key); */
+
+
+ memcpy(link_key.mac.u8, mac_addr.u8, sizeof(link_key.mac));
+ if (TB_RC_OK != hal_find_lidx_by_link_key(&link_key, &lidx)) {
+ TB_ERROR("link not found");
+ // Nathan: json_error(rx_frame, BRDG_RET_INPUT_INVALID); ??
+ }
+ TB_TRACE("LIDX: %d", lidx);
+
+ /* Warning: Should derive the mac block from hw_cfg */
+ json_stats(rx_frame, lidx, MB1);
+ }
+ } else if (strcmp(operation, "sla_set") == 0) {
+ if ((strlen(itype) == 0) || (strlen(iinst) == 0) || (strlen(mac) == 0)
+ || (strlen(cir) == 0) || (strlen(eir) == 0)) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ if (0 != strcmp("olt", itype)) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ lsm_link_sla_spec_t sla_spec = {.cir_Kbps = strtoul(cir, NULL, 10),
+ .eir_Kbps = strtoul(eir, NULL, 10)
+ };
+ lsm_link_key_t link_key = {.ifc_type = TB_IFC_TYPE_OLT,
+ .ifc_inst = strtoul(iinst, NULL, 10)
+ };
+
+ memcpy(link_key.mac.u8, mac_addr.u8, sizeof(link_key.mac));
+
+ tb_rc rc = json_sla_set(rx_frame, &link_key, &sla_spec);
+
+ TB_TRACE("json_sla_set returned %d (%s)", rc, tb_strerror(rc));
+ }
+ }
+ } else if (strcmp(operation, "sla_get") == 0) {
+ if ((strlen(itype) == 0) || (strlen(iinst) == 0) || (strlen(mac) == 0)) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ if (0 != strcmp("olt", itype)) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ tb_mac_address_str_t mac_str;
+ lsm_link_sla_spec_t sla_spec;
+ lsm_link_key_t link_key = {.ifc_type = TB_IFC_TYPE_OLT,
+ .ifc_inst = strtoul(iinst, NULL, 10)
+ };
+
+ memcpy(link_key.mac.u8, mac_addr.u8, sizeof(link_key.mac));
+
+ tb_mac_address_to_str(link_key.mac.u8, mac_str);
+
+ tb_rc rc = json_sla_get(rx_frame, &link_key, &sla_spec);
+
+ TB_TRACE("json_sla_get returned %d (%s)", rc, tb_strerror(rc));
+ }
+ }
+ } else if (strcmp(operation, "fec_set") == 0) {
+ if ((strlen(mode) == 0)) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ tb_rc rc = TB_RC_OK;
+ tb_ifc_key_t ifc_key = {.type = TB_IFC_TYPE_OLT,
+ .inst = 0,
+ .subinst = TB_IFC_SUBINST_NONE
+ };
+
+ if (strncmp(mode, "enabled", 7) == 0) {
+ rc = json_fec_set(rx_frame, &ifc_key, true);
+ } else {
+ rc = json_fec_set(rx_frame, &ifc_key, false);
+ }
+
+ TB_TRACE("json_fec_set returned %d (%s)", rc, tb_strerror(rc));
+ }
+ } else if (strcmp(operation, "fec_get") == 0) {
+ tb_ifc_key_t ifc_key = {.type = TB_IFC_TYPE_OLT,
+ .inst = 0,
+ .subinst = TB_IFC_SUBINST_NONE
+ };
+
+ tb_rc rc = json_fec_get(rx_frame, &ifc_key);
+
+ TB_TRACE("json_fec_get returned %d (%s)", rc, tb_strerror(rc));
+
+ } else if (strcmp(operation, "tag_mode_set") == 0) {
+ if ((strlen(tag_mode) == 0)) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ tb_rc rc = TB_RC_OK;
+
+ rc = json_tag_mode_set(rx_frame, tag_mode);
+
+
+ TB_TRACE("json_tag_mode_set returned %d (%s)", rc, tb_strerror(rc));
+ }
+ } else if (strcmp(operation, "tag_mode_get") == 0) {
+
+ tb_rc rc = TB_RC_OK;
+
+ rc = json_tag_mode_get(rx_frame);
+
+ TB_TRACE("json_tag_mode_get returned %d (%s)", rc, tb_strerror(rc));
+
+ } else if (strcmp(operation, "flows_add") == 0) {
+ if ((strlen(itype) == 0) || (strlen(iinst) == 0) || (strlen(mac) == 0)
+ || (strlen(svid) == 0) || (strlen(cvid) == 0)
+ || (strlen(code) == 0)) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ sw_rec_key_t sw_rec_key = { .outer_vid = strtoul(svid, NULL, 10),
+ .inner_vid = strtoul(cvid, NULL, 10)
+ };
+ tb_ifc_key_t ingress_ifc_key = {.type = TB_IFC_TYPE_UNKNOWN,
+ .inst = strtoul(iinst, NULL, 10),
+ .subinst = TB_IFC_SUBINST_NONE
+ };
+ lsm_link_key_t link_key = {.ifc_type = TB_IFC_TYPE_OLT,
+ .ifc_inst = strtoul(iinst, NULL, 10)
+ };
+ port_vlan_op_cfg_t port_vlan_op_cfg = {
+ { port_vlan_op_type_unspecified, 0 },
+ { port_vlan_op_type_unspecified, 0 }
+ };
+
+ if (strncmp(tpid, "88a8", 5) == 0) {
+ if (strncmp(code, "pop", 4) == 0) {
+ port_vlan_op_cfg[0].op_type = port_vlan_op_type_pop;
+ TB_TRACE("setting stag pop");
+
+ } else if (strncmp(code, "push", 4) == 0) {
+ port_vlan_op_cfg[0].op_type = port_vlan_op_type_push;
+ port_vlan_op_cfg[0].op_arg = strtoul(vid, NULL, 10);
+ TB_TRACE("setting stag push");
+ }
+ } else if (strncmp(tpid, "8100", 5) == 0) {
+ if (strncmp(code, "pop", 4) == 0) {
+ port_vlan_op_cfg[1].op_type = port_vlan_op_type_pop;
+ TB_TRACE("settting ctag pop");
+
+ } else if (strncmp(code, "push", 4) == 0) {
+ port_vlan_op_cfg[1].op_type = port_vlan_op_type_push;
+ port_vlan_op_cfg[1].op_arg = strtoul(vid, NULL, 10);
+ TB_TRACE("setting ctag push");
+ }
+ }
+
+ tb_str_to_buf(link_key.mac.u8, mac, sizeof(mac_addr));
+
+ if (strncmp(itype,"olt", 4) == 0) {
+ ingress_ifc_key.type = TB_IFC_TYPE_OLT;
+ /* If ingress type is OLT, then set the subinst to LLID */
+ ingress_ifc_key.subinst = lsm_find_llid_by_link_key(&link_key);
+ if (gpon_device_p()) {
+ ingress_ifc_key.subinst += (0x1000 + BRDG_XGEM_ALLOC_ID_LIDX_THRESHOLD);
+ }
+
+ } else if (strncmp(itype,"eth", 4) == 0) {
+ ingress_ifc_key.type = TB_IFC_TYPE_ETHERNET;
+ if (gpon_device_p()) {
+ link_key.ifc_type = TB_IFC_TYPE_ALLOC_ID;
+ }
+ /* If ingress type is Ethernet, set the default dest to the LLID */
+ sw_rec_key.default_dest = lsm_find_llid_by_link_key(&link_key);
+ if (sw_rec_key.default_dest == TB_IFC_SUBINST_NONE) {
+ if (gpon_device_p()) {
+ sw_rec_key.default_dest = 0x10000 | 0x10bc; // FIXME temporary hard-coded pseudo-broadcast xgem id
+ } else {
+ sw_rec_key.default_dest = 0x10000 | 0x7ffe; // FIXME not sure if we should assume EPON or fail in the EPON case
+ }
+ }
+ } else {
+ tb_printf("UNKNOWN IFC TYPE\n");
+ }
+
+ tb_rc rc = json_flows_add(rx_frame, &ingress_ifc_key, &sw_rec_key,
+ port_vlan_op_cfg);
+
+ TB_TRACE("json_flows_add returned %d (%s)", rc, tb_strerror(rc));
+ }
+ } else if (strcmp(operation, "flows_delete") == 0) {
+ if ((strlen(itype) == 0) || (strlen(iinst) == 0) || (strlen(mac) == 0)
+ || (strlen(svid) == 0) || (strlen(cvid) == 0)) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ sw_rec_key_t sw_rec_key = {.outer_vid = strtoul(svid, NULL, 10),
+ .inner_vid = strtoul(cvid, NULL, 10)
+ };
+ tb_ifc_key_t ingress_ifc_key = {.type = TB_IFC_TYPE_UNKNOWN,
+ .inst = strtoul(iinst, NULL, 10),
+ .subinst = TB_IFC_SUBINST_NONE
+ };
+ lsm_link_key_t link_key = {.ifc_type = TB_IFC_TYPE_OLT,
+ .ifc_inst = strtoul(iinst, NULL, 10)
+ };
+ tb_str_to_buf(link_key.mac.u8, mac, sizeof(mac_addr));
+
+
+ if (strncmp(itype,"olt", 4) == 0) {
+ ingress_ifc_key.type = TB_IFC_TYPE_OLT;
+ /* If ingress type is OLT, then set the subinst to LLID */
+ ingress_ifc_key.subinst = lsm_find_llid_by_link_key(&link_key);
+ /* if (gpon_device_p()) { */
+ /* ingress_ifc_key.subinst += (0x1000 + BRDG_XGEM_ALLOC_ID_LIDX_THRESHOLD); */
+ /* } */
+
+ } else if (strncmp(itype,"eth", 4) == 0) {
+ ingress_ifc_key.type = TB_IFC_TYPE_ETHERNET;
+ if (gpon_device_p()) {
+ link_key.ifc_type = TB_IFC_TYPE_ALLOC_ID;
+ }
+ /* If ingress type is Ethernet, set the default dest to the LLID */
+ sw_rec_key.default_dest = lsm_find_llid_by_link_key(&link_key);
+
+ } else {
+ tb_printf("UNKNOWN IFC TYPE\n");
+ }
+
+ tb_rc rc = json_flows_delete(rx_frame, &ingress_ifc_key, &sw_rec_key);
+
+ TB_TRACE("json_flows_delete returned %d (%s)", rc, tb_strerror(rc));
+ }
+ } else if (strcmp(operation, "flows") == 0) {
+ tb_rc rc = json_flows_get(rx_frame);
+ TB_TRACE("json_flows_get returned %d (%s)", rc, tb_strerror(rc));
+ } else if (strcmp(operation, "mode_set") == 0) {
+ if (strlen(mode) == 0) {
+ json_error(rx_frame, BRDG_RET_INPUT_INVALID);
+ } else {
+ tb_rc rc = TB_RC_OK;
+
+ if (strncmp(mode, "GPON", 5) == 0) {
+ if (olt_device_p()) {
+ rc = json_mode_set(rx_frame, MANDATA_PON_TYPE_10G_GPON_OLT);
+ } else {
+ rc = json_mode_set(rx_frame, MANDATA_PON_TYPE_10G_GPON_ONU);
+ }
+ } else if (strncmp(mode, "EPON", 5) == 0) {
+ if (olt_device_p()) {
+ rc = json_mode_set(rx_frame, MANDATA_PON_TYPE_10G_EPON_OLT);
+ } else {
+ rc = json_mode_set(rx_frame, MANDATA_PON_TYPE_10G_EPON_ONU);
+ }
+ } else {
+ TB_WARNING("Unrecognized mode %s", mode);
+ }
+ TB_TRACE("json_mode_set returned %d (%s)", rc, tb_strerror(rc));
+ }
+ } else if (strcmp(operation, "cli") == 0) {
+ run_command(cmd, 0);
+ json_cli_cmd(rx_frame);
+ } else if (strcmp(operation, "getRequest") == 0) {
+ mac_address deviceMac;
+ tb_str_to_buf(deviceMac.u8, mac, sizeof(mac_addr));
+ oam_snd_get_request(&deviceMac);
+ } else {
+ TB_WARNING("unknown operation \"%s\" -- ignoring", operation);
+ }
+
+ memset(operation, 0, SIZE_OF_OPERATION);
+ memset(itype, 0, SIZE_OF_ITYPE);
+ memset(iinst, 0, SIZE_OF_IINST);
+ memset(svid, 0, SVID_STR_LEN);
+ memset(cvid, 0, CVID_STR_LEN);
+ memset(cmd, 0, SIZE_OF_CMD);
+ }
+
+ return 0;
+
+} /* process_json() */
+
+/* JSON input mode
+ *
+ * Syntax:
+ * json
+ */
+static int do_json(UNUSED_ARG cmd_tbl_t * cmdtp, UNUSED_ARG int flag, UNUSED_ARG int argc, char *const argv[])
+{
+ tb_pkt_deprec_t *p_fake_frame;
+ tb_dbug_lvl_t original_dbug_lvl;
+ p_fake_frame = &fake_frame;
+
+ memset(p_fake_frame, 0, sizeof(tb_pkt_deprec_t));
+ /* No spaces allowed during json input on the command line or else
+ * the json is considered as more then one argument (argc > 2) */
+ p_fake_frame->num_bytes = 8 /* preamble */
+ + 6 /* dest */
+ + 6 /* source */
+ + 2 /* type */
+ + 4 /* 'json' */
+ + 1 /* space */
+ + strlen(argv[1])
+ + 4; /* CRC */
+ memcpy(&p_fake_frame->preamble_start[START_OF_JSON_UNTAGGED], argv[1], strlen(argv[1]));
+ command_line_json = true;
+
+ /* silence debug while we process a command */
+ original_dbug_lvl = tb_dbug_lvl;
+ if ((tb_dbug_lvl == TB_DBUG_LVL_ERROR) || (tb_dbug_lvl == TB_DBUG_LVL_WARNING)) {
+ tb_dbug_lvl = TB_DBUG_LVL_SILENT;
+ }
+
+ process_json(p_fake_frame);
+ tb_dbug_lvl = original_dbug_lvl;
+ return 0;
+} /* do_json */
+
+/**************************************************/
+U_BOOT_CMD(json, 2, 0, do_json, "enter json mode", "\r\n");
diff --git a/voltha/adapters/tibit_olt/tibit_olt.py b/voltha/adapters/tibit_olt/tibit_olt.py
index 5d9ab81..9b2964b 100644
--- a/voltha/adapters/tibit_olt/tibit_olt.py
+++ b/voltha/adapters/tibit_olt/tibit_olt.py
@@ -329,8 +329,9 @@
# later use. The linkid is the macid returned.
self.vlan_to_device_ids[vlan_id] = (device.id, device.parent_id, macid.get('macid', 0))
- # Give the ONUs a chance to arrive before starting metric collection
- reactor.callLater(5.0, self.start_kpi_collection, device.id)
+ ### KPI Metrics - Work in progress feature - Disabling for now
+ ### Give the ONUs a chance to arrive before starting metric collection
+ ### reactor.callLater(5.0, self.start_kpi_collection, device.id)
def _olt_side_onu_activation(self, serial):
"""