Пример #1
0
 def send_proxied_message(self, proxy_address, msg):
     self.log.info('sending-proxied-message')
     if isinstance(msg, FlowTable):
         stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
         self.log.info('pushing-onu-flow-table', port=msg.port)
         res = stub.UpdateFlowTable(msg)
         self.adapter_agent.receive_proxied_message(proxy_address, res)
     elif isinstance(msg, PonSimMetricsRequest):
         stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
         self.log.info('proxying onu stats request', port=msg.port)
         res = stub.GetStats(msg)
         self.adapter_agent.receive_proxied_message(proxy_address, res)
Пример #2
0
 def collect_port_metrics(self, channel):
     rtrn_port_metrics = dict()
     stub = ponsim_pb2_grpc.PonSimStub(channel)
     stats = stub.GetStats(ponsim_pb2.PonSimMetricsRequest(port=0))
     rtrn_port_metrics['pon'] = self.extract_pon_metrics(stats)
     rtrn_port_metrics['nni'] = self.extract_nni_metrics(stats)
     return rtrn_port_metrics
Пример #3
0
    def update_flow_table(self, flows):
        stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
        self.log.info('pushing-olt-flow-table')
        for flow in flows:
            classifier_info = {}
            for field in fd.get_ofb_fields(flow):
                if field.type == fd.ETH_TYPE:
                    classifier_info['eth_type'] = field.eth_type
                    self.log.debug('field-type-eth-type',
                                   eth_type=classifier_info['eth_type'])
                elif field.type == fd.IP_PROTO:
                    classifier_info['ip_proto'] = field.ip_proto
                    self.log.debug('field-type-ip-proto',
                                   ip_proto=classifier_info['ip_proto'])
            if ('ip_proto' in classifier_info and
                (classifier_info['ip_proto'] == 17
                 or classifier_info['ip_proto'] == 2)) or (
                     'eth_type' in classifier_info
                     and classifier_info['eth_type'] == 0x888e):
                for action in fd.get_actions(flow):
                    if action.type == ofp.OFPAT_OUTPUT:
                        action.output.port = ofp.OFPP_CONTROLLER
            self.log.info('out_port', out_port=fd.get_out_port(flow))

        stub.UpdateFlowTable(FlowTable(port=0, flows=flows))
        self.log.info('success')
Пример #4
0
    def reconcile(self, device):
        self.log.info('reconciling-OLT-device-starts')

        if not device.host_and_port:
            device.oper_status = OperStatus.FAILED
            device.reason = 'No host_and_port field provided'
            self.adapter_agent.update_device(device)
            return

        try:
            stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
            info = stub.GetDeviceInfo(Empty())
            log.info('got-info', info=info)
            # TODO: Verify we are connected to the same device we are
            # reconciling - not much data in ponsim to differentiate at the
            # time
            device.oper_status = OperStatus.ACTIVE
            self.adapter_agent.update_device(device)
            self.ofp_port_no = info.nni_port
            self.nni_port = self._get_nni_port()
        except Exception, e:
            log.exception('device-unreachable', e=e)
            device.connect_status = ConnectStatus.UNREACHABLE
            device.oper_status = OperStatus.UNKNOWN
            self.adapter_agent.update_device(device)
            return
Пример #5
0
    def update_flow_table(self, flows):
        stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
        self.log.info('pushing-olt-flow-table')

        eapol_flows = {}
        eapol_flow_without_vlan = False

        for flow in flows:
            classifier_info = self.get_classifier_info(flow)

            self.log.debug('classifier_info', classifier_info=classifier_info)

            if IP_PROTO in classifier_info:
                if classifier_info[IP_PROTO] == 17:
                    if UDP_SRC in classifier_info:
                        if classifier_info[UDP_SRC] == 68:
                            self.log.info('dhcp upstream flow add')
                        elif classifier_info[UDP_SRC] == 67:
                            self.log.info('dhcp downstream flow add')
                    self.to_controller(flow)
                elif classifier_info[IP_PROTO] == 2:
                    self.log.info('igmp flow add')
                    self.to_controller(flow)
                else:
                    self.log.warn("Invalid-Classifier-to-handle",
                                   classifier_info=classifier_info)
            elif ETH_TYPE in classifier_info:
                if classifier_info[ETH_TYPE] == EAP_ETH_TYPE:
                    self.log.info('eapol flow add')
                    self.to_controller(flow)
                    if VLAN_VID in classifier_info:
                        eapol_flows[classifier_info[VLAN_VID]] = flow
                    else:
                        eapol_flow_without_vlan = True

        # The OLT app is now adding EAPOL flows with VLAN_VID=4091 but Ponsim can't
        # properly handle this because it uses VLAN_VID to encode the UNI port ID.
        # Add an EAPOL trap flow with no VLAN_VID match if we see the 4091 match.
        if 4091 in eapol_flows and not eapol_flow_without_vlan:
            new_eapol_flow = [
                fd.mk_flow_stat(
                    priority=10000,
                    match_fields=[fd.in_port(1), fd.eth_type(EAP_ETH_TYPE)],
                    actions=[fd.output(ofp.OFPP_CONTROLLER)]
                )
            ]
            flows.extend(new_eapol_flow)
            self.log.info('add eapol flow with no VLAN_VID match')

        stub.UpdateFlowTable(FlowTable(
            port=0,
            flows=flows
        ))
        self.log.info('success')
Пример #6
0
    def send_proxied_message(self, proxy_address, msg):
        self.log.debug('sending-proxied-message')
        if isinstance(msg, FlowTable):
            stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
            self.log.info('pushing-onu-flow-table', port=msg.port)

            # Extract ctag -> uni_port mapping from ONU flows.
            # Below we assume that a downstream flow whose VLAN_VID is not
            # equal to the logcal port is stripping the ctag.
            # If we find such a flow we add the mapping to the ctag_map.
            # Note that this wouldn't be necessary if we actually knew the logical
            # port that an upstream packet arrived on.
            logical_port_id = "uni-{}".format(msg.port)
            logical_port = self.adapter_agent.get_logical_port(self.logical_device_id, logical_port_id)
            if logical_port:
                uni_port_id = logical_port.device_port_no
                ctag = None

                for flow in msg.flows:
                    classifier_info = self.get_classifier_info(flow)
                    self.log.debug('classifier_info', classifier_info=classifier_info)

                    if VLAN_VID in classifier_info and IN_PORT in classifier_info:
                        if classifier_info[IN_PORT] != uni_port_id and classifier_info[VLAN_VID] != msg.port:
                            if ctag is not None:
                                self.log.error('more than one ctag inferred', ctag1=ctag, ctag2=classifier_info[VLAN_VID])
                            ctag = classifier_info[VLAN_VID]

                self.update_ctag_map(ctag, msg.port)
            else:
                self.log.error('no logical port found', id=logical_port_id)

            res = stub.UpdateFlowTable(msg)
            self.adapter_agent.receive_proxied_message(proxy_address, res)
        elif isinstance(msg, PonSimMetricsRequest):
            stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
            self.log.debug('proxying onu stats request', port=msg.port)
            res = stub.GetStats(msg)
            self.adapter_agent.receive_proxied_message(proxy_address, res)
Пример #7
0
    def rcv_grpc(self):
        """
        This call establishes a GRPC stream to receive frames.
        """
        stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())

        # Attempt to establish a grpc stream with the remote ponsim service
        self.frames = stub.ReceiveFrames(Empty())

        self.log.info('start-receiving-grpc-frames')

        try:
            for frame in self.frames:
                self.log.info('received-grpc-frame',
                              frame_len=len(frame.payload))
                self._rcv_frame(frame.payload)

        except _Rendezvous, e:
            log.warn('grpc-connection-lost', message=e.message)
Пример #8
0
    def packet_out(self, egress_port, msg):
        self.log.debug('sending-packet-out', egress_port=egress_port,
                       msg_hex=hexify(msg))
        pkt = Ether(msg)
        out_pkt = pkt
        self.log.debug("packet_out: incoming: %s" % pkt.summary())
        if egress_port != self.nni_port.port_no:
            # don't do the vlan manipulation for the NNI port, vlans are already correct
            if pkt.haslayer(Dot1Q):
                if pkt.haslayer(Dot1AD):
                    outer_shim = pkt.getlayer(Dot1AD)
                else:
                    outer_shim = pkt.getlayer(Dot1Q)
                if isinstance(outer_shim.payload, Dot1Q):
                    # If double tag, remove the outer tag
                    out_pkt = (
                            Ether(src=pkt.src, dst=pkt.dst,
                                  type=outer_shim.type) /
                            outer_shim.payload
                    )
                else:
                    out_pkt = pkt
            else:
                # Add egress port as VLAN tag
                out_pkt = (
                    Ether(src=pkt.src, dst=pkt.dst) /
                    Dot1Q(vlan=egress_port, type=pkt.type) /
                    pkt.payload
                )
        self.log.debug("packet_out: outgoing: %s" % out_pkt.summary())

        # TODO need better way of mapping logical ports to PON ports
        out_port = self.nni_port.port_no if egress_port == self.nni_port.port_no else 1

        if self.ponsim_comm == 'grpc':
            # send over grpc stream
            stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
            frame = PonSimFrame(id=self.device_id, payload=str(out_pkt), out_port=out_port)
            stub.SendFrame(frame)
        else:
            # send over frameio
            self.io_port.send(str(out_pkt))
Пример #9
0
    def reenable(self):
        self.log.info('re-enabling', device_id=self.device_id)

        # Get the latest device reference
        device = self.adapter_agent.get_device(self.device_id)

        # Set the ofp_port_no and nni_port in case we bypassed the reconcile
        # process if the device was in DISABLED state on voltha restart
        if not self.ofp_port_no and not self.nni_port:
            stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
            info = stub.GetDeviceInfo(Empty())
            log.info('got-info', info=info)
            self.ofp_port_no = info.nni_port
            self.nni_port = self._get_nni_port()

        # Update the connect status to REACHABLE
        device.connect_status = ConnectStatus.REACHABLE
        self.adapter_agent.update_device(device)

        # Set all ports to enabled
        self.adapter_agent.enable_all_ports(self.device_id)

        device = self.adapter_agent.get_device(device.id)
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)

        # Reenable all child devices
        self.adapter_agent.update_child_devices_state(device.id,
                                                      admin_state=AdminState.ENABLED)

        if self.ponsim_comm == 'grpc':
            # establish frame grpc-stream
            reactor.callInThread(self.rcv_grpc)
        else:
            # finally, open the frameio port to receive in-band packet_in messages
            self.io_port = registry('frameio').open_port(
                self.interface, self.rcv_io, is_inband_frame)

        self.start_kpi_collection(device.id)

        self.log.info('re-enabled', device_id=device.id)
Пример #10
0
    def packet_out(self, egress_port, msg):
        self.log.info('sending-packet-out',
                      egress_port=egress_port,
                      msg=hexify(msg))
        pkt = Ether(msg)
        out_pkt = pkt
        if egress_port != self.nni_port.port_no:
            # don't do the vlan manipulation for the NNI port, vlans are already correct
            out_pkt = (Ether(src=pkt.src, dst=pkt.dst) /
                       Dot1Q(vlan=egress_port, type=pkt.type) / pkt.payload)

        # TODO need better way of mapping logical ports to PON ports
        out_port = self.nni_port.port_no if egress_port == self.nni_port.port_no else 1

        if self.ponsim_comm == 'grpc':
            # send over grpc stream
            stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
            frame = PonSimFrame(id=self.device_id,
                                payload=str(out_pkt),
                                out_port=out_port)
            stub.SendFrame(frame)
        else:
            # send over frameio
            self.io_port.send(str(out_pkt))
Пример #11
0
    def reenable(self):
        self.log.info('re-enabling', device_id=self.device_id)

        # Get the latest device reference
        device = self.adapter_agent.get_device(self.device_id)

        # Set the ofp_port_no and nni_port in case we bypassed the reconcile
        # process if the device was in DISABLED state on voltha restart
        if not self.ofp_port_no and not self.nni_port:
            stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
            info = stub.GetDeviceInfo(Empty())
            log.info('got-info', info=info)
            self.ofp_port_no = info.nni_port
            self.nni_port = self._get_nni_port()

        # Update the connect status to REACHABLE
        device.connect_status = ConnectStatus.REACHABLE
        self.adapter_agent.update_device(device)

        # Set all ports to enabled
        self.adapter_agent.enable_all_ports(self.device_id)

        ld = LogicalDevice(
            # not setting id and datapth_id will let the adapter agent pick id
            desc=ofp_desc(hw_desc='simulated pon',
                          sw_desc='simulated pon',
                          serial_num=uuid4().hex,
                          dp_desc='n/a'),
            switch_features=ofp_switch_features(
                n_buffers=256,  # TODO fake for now
                n_tables=2,  # TODO ditto
                capabilities=(  # TODO and ditto
                    OFPC_FLOW_STATS
                    | OFPC_TABLE_STATS
                    | OFPC_PORT_STATS
                    | OFPC_GROUP_STATS)),
            root_device_id=device.id)
        mac_address = "AA:BB:CC:DD:EE:FF"
        ld_initialized = self.adapter_agent.create_logical_device(
            ld, dpid=mac_address)
        cap = OFPPF_1GB_FD | OFPPF_FIBER
        self.adapter_agent.add_logical_port(
            ld_initialized.id,
            LogicalPort(id='nni',
                        ofp_port=ofp_port(
                            port_no=self.ofp_port_no,
                            hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' %
                                                     self.ofp_port_no),
                            name='nni',
                            config=0,
                            state=OFPPS_LIVE,
                            curr=cap,
                            advertised=cap,
                            peer=cap,
                            curr_speed=OFPPF_1GB_FD,
                            max_speed=OFPPF_1GB_FD),
                        device_id=device.id,
                        device_port_no=self.nni_port.port_no,
                        root_port=True))

        device = self.adapter_agent.get_device(device.id)
        device.parent_id = ld_initialized.id
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)
        self.logical_device_id = ld_initialized.id

        # Reenable all child devices
        self.adapter_agent.update_child_devices_state(
            device.id, admin_state=AdminState.ENABLED)

        if self.ponsim_comm == 'grpc':
            # establish frame grpc-stream
            reactor.callInThread(self.rcv_grpc)
        else:
            # finally, open the frameio port to receive in-band packet_in messages
            self.io_port = registry('frameio').open_port(
                self.interface, self.rcv_io, is_inband_frame)

        self.start_kpi_collection(device.id)

        self.log.info('re-enabled', device_id=device.id)
Пример #12
0
    def activate(self, device):
        self.log.info('activating')

        if not device.host_and_port:
            device.oper_status = OperStatus.FAILED
            device.reason = 'No host_and_port field provided'
            self.adapter_agent.update_device(device)
            return

        stub = ponsim_pb2_grpc.PonSimStub(self.get_channel())
        info = stub.GetDeviceInfo(Empty())
        log.info('got-info', info=info)

        device.root = True
        device.vendor = 'ponsim'
        device.model = 'n/a'
        device.serial_number = device.host_and_port
        device.connect_status = ConnectStatus.REACHABLE
        self.adapter_agent.update_device(device)

        # Now set the initial PM configuration for this device
        self.pm_metrics = AdapterPmMetrics(device)
        pm_config = self.pm_metrics.make_proto()
        log.info("initial-pm-config", pm_config=pm_config)
        self.adapter_agent.update_device_pm_config(pm_config, init=True)

        # Setup alarm handler
        self.alarms = AdapterAlarms(self.adapter, device)

        nni_port = Port(port_no=info.nni_port,
                        label='NNI facing Ethernet port',
                        type=Port.ETHERNET_NNI,
                        admin_state=AdminState.ENABLED,
                        oper_status=OperStatus.ACTIVE)
        self.nni_port = nni_port
        self.adapter_agent.add_port(device.id, nni_port)
        self.adapter_agent.add_port(
            device.id,
            Port(port_no=1,
                 label='PON port',
                 type=Port.PON_OLT,
                 admin_state=AdminState.ENABLED,
                 oper_status=OperStatus.ACTIVE))

        ld = LogicalDevice(
            # not setting id and datapath_id.  Adapter agent will pick the id
            # and will pick the datapath_id is it is not provided
            desc=ofp_desc(
                hw_desc='simualted pon',
                sw_desc='simualted pon',
                # serial_num=uuid4().hex,
                serial_num=device.serial_number,
                dp_desc='n/a'),
            switch_features=ofp_switch_features(
                n_buffers=256,  # TODO fake for now
                n_tables=2,  # TODO ditto
                capabilities=(  # TODO and ditto
                    OFPC_FLOW_STATS
                    | OFPC_TABLE_STATS
                    | OFPC_PORT_STATS
                    | OFPC_GROUP_STATS)),
            root_device_id=device.id)
        mac_address = "AA:BB:CC:DD:EE:FF"
        ld_initialized = self.adapter_agent.create_logical_device(
            ld, dpid=mac_address)
        cap = OFPPF_1GB_FD | OFPPF_FIBER
        self.ofp_port_no = info.nni_port
        self.adapter_agent.add_logical_port(
            ld_initialized.id,
            LogicalPort(id='nni',
                        ofp_port=ofp_port(
                            port_no=info.nni_port,
                            hw_addr=mac_str_to_tuple('00:00:00:00:00:%02x' %
                                                     info.nni_port),
                            name='nni',
                            config=0,
                            state=OFPPS_LIVE,
                            curr=cap,
                            advertised=cap,
                            peer=cap,
                            curr_speed=OFPPF_1GB_FD,
                            max_speed=OFPPF_1GB_FD),
                        device_id=device.id,
                        device_port_no=nni_port.port_no,
                        root_port=True))

        device = self.adapter_agent.get_device(device.id)
        device.parent_id = ld_initialized.id
        device.oper_status = OperStatus.ACTIVE
        self.adapter_agent.update_device(device)
        self.logical_device_id = ld_initialized.id

        # register ONUS
        for onu in info.onus:
            vlan_id = onu.uni_port
            self.adapter_agent.child_device_detected(
                parent_device_id=device.id,
                parent_port_no=1,
                child_device_type='ponsim_onu',
                proxy_address=Device.ProxyAddress(device_id=device.id,
                                                  channel_id=vlan_id),
                admin_state=AdminState.ENABLED,
                vlan=vlan_id,
                serial_number=onu.serial_number)

        if self.ponsim_comm == 'grpc':
            self.log.info('starting-frame-grpc-stream')
            reactor.callInThread(self.rcv_grpc)
            self.log.info('started-frame-grpc-stream')
        else:
            # finally, open the frameio port to receive in-band packet_in messages
            self.log.info('registering-frameio')
            self.io_port = registry('frameio').open_port(
                self.interface, self.rcv_io, is_inband_frame)
            self.log.info('registered-frameio')

        # Start collecting stats from the device after a brief pause
        self.start_kpi_collection(device.id)