| 1 |  |  | """NApp responsible to discover new switches and hosts.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 2 | 1 |  | import struct | 
            
                                                                                                            
                            
            
                                    
            
            
                | 3 | 1 |  | import time | 
            
                                                                                                            
                            
            
                                    
            
            
                | 4 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 5 | 1 |  | import requests | 
            
                                                                                                            
                            
            
                                    
            
            
                | 6 | 1 |  | from flask import jsonify, request | 
            
                                                                                                            
                            
            
                                    
            
            
                | 7 | 1 |  | from pyof.foundation.basic_types import DPID, UBInt32 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 8 | 1 |  | from pyof.foundation.network_types import LLDP, VLAN, Ethernet, EtherType | 
            
                                                                                                            
                            
            
                                    
            
            
                | 9 | 1 |  | from pyof.v0x04.common.action import ActionOutput as AO13 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 10 | 1 |  | from pyof.v0x04.common.port import PortNo as Port13 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 11 | 1 |  | from pyof.v0x04.controller2switch.packet_out import PacketOut as PO13 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 12 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 13 | 1 |  | from kytos.core import KytosEvent, KytosNApp, log, rest | 
            
                                                                                                            
                            
            
                                    
            
            
                | 14 | 1 |  | from kytos.core.helpers import alisten_to, listen_to | 
            
                                                                                                            
                            
            
                                    
            
            
                | 15 | 1 |  | from kytos.core.link import Link | 
            
                                                                                                            
                            
            
                                    
            
            
                | 16 | 1 |  | from napps.kytos.of_core.msg_prios import of_msg_prio | 
            
                                                                                                            
                            
            
                                    
            
            
                | 17 | 1 |  | from napps.kytos.of_lldp import constants, settings | 
            
                                                                                                            
                            
            
                                    
            
            
                | 18 | 1 |  | from napps.kytos.of_lldp.managers import LivenessManager, LoopManager | 
            
                                                                                                            
                            
            
                                    
            
            
                | 19 | 1 |  | from napps.kytos.of_lldp.managers.loop_manager import LoopState | 
            
                                                                                                            
                            
            
                                    
            
            
                | 20 | 1 |  | from napps.kytos.of_lldp.utils import get_cookie | 
            
                                                                                                            
                            
            
                                    
            
            
                | 21 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 22 | 1 |  | from .controllers import LivenessController | 
            
                                                                                                            
                            
            
                                    
            
            
                | 23 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 24 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 25 | 1 |  | class Main(KytosNApp): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 26 |  |  |     """Main OF_LLDP NApp Class.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 27 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 28 | 1 |  |     def setup(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 29 |  |  |         """Make this NApp run in a loop.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 30 | 1 |  |         self.vlan_id = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 31 | 1 |  |         self.polling_time = settings.POLLING_TIME | 
            
                                                                                                            
                            
            
                                    
            
            
                | 32 | 1 |  |         if hasattr(settings, "FLOW_VLAN_VID"): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 33 | 1 |  |             self.vlan_id = settings.FLOW_VLAN_VID | 
            
                                                                                                            
                            
            
                                    
            
            
                | 34 | 1 |  |         self.liveness_dead_multipler = settings.LIVENESS_DEAD_MULTIPLIER | 
            
                                                                                                            
                            
            
                                    
            
            
                | 35 | 1 |  |         self.execute_as_loop(self.polling_time) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 36 | 1 |  |         self.loop_manager = LoopManager(self.controller) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 37 | 1 |  |         self.dead_interval = self.polling_time * self.liveness_dead_multipler | 
            
                                                                                                            
                            
            
                                    
            
            
                | 38 | 1 |  |         self.liveness_controller = self.get_liveness_controller() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 39 | 1 |  |         self.liveness_controller.bootstrap_indexes() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 40 | 1 |  |         self.liveness_manager = LivenessManager(self.controller) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 41 | 1 |  |         Link.register_status_func(f"{self.napp_id}_liveness", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 42 |  |  |                                   LivenessManager.link_status_hook_liveness) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 43 | 1 |  |         self.table_group = {"base": 0} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 44 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 45 | 1 |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 46 | 1 |  |     def get_liveness_controller() -> LivenessController: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 47 |  |  |         """Get LivenessController.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 48 |  |  |         return LivenessController() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 49 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 50 | 1 |  |     def execute(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 51 |  |  |         """Send LLDP Packets every 'POLLING_TIME' seconds to all switches.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 52 | 1 |  |         switches = list(self.controller.switches.values()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 53 | 1 |  |         for switch in switches: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 54 | 1 |  |             try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 55 | 1 |  |                 of_version = switch.connection.protocol.version | 
            
                                                                                                            
                            
            
                                    
            
            
                | 56 |  |  |             except AttributeError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 57 |  |  |                 of_version = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 58 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 59 | 1 |  |             if not switch.is_connected(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 60 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 61 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 62 | 1 |  |             if of_version == 0x04: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 63 | 1 |  |                 port_type = UBInt32 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 64 | 1 |  |                 local_port = Port13.OFPP_LOCAL | 
            
                                                                                                            
                            
            
                                    
            
            
                | 65 |  |  |             else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 66 |  |  |                 # skip the current switch with unsupported OF version | 
            
                                                                                                            
                            
            
                                    
            
            
                | 67 |  |  |                 continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 68 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 69 | 1 |  |             interfaces = list(switch.interfaces.values()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 70 | 1 |  |             for interface in interfaces: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 71 |  |  |                 # Interface marked to receive lldp packet | 
            
                                                                                                            
                            
            
                                    
            
            
                | 72 |  |  |                 # Only send LLDP packet to active interface | 
            
                                                                                                            
                            
            
                                    
            
            
                | 73 | 1 |  |                 if(not interface.lldp or not interface.is_active() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 74 |  |  |                    or not interface.is_enabled()): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 75 |  |  |                     continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 76 |  |  |                 # Avoid the interface that connects to the controller. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 77 | 1 |  |                 if interface.port_number == local_port: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 78 |  |  |                     continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 79 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 80 | 1 |  |                 lldp = LLDP() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 81 | 1 |  |                 lldp.chassis_id.sub_value = DPID(switch.dpid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 82 | 1 |  |                 lldp.port_id.sub_value = port_type(interface.port_number) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 83 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 84 | 1 |  |                 ethernet = Ethernet() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 85 | 1 |  |                 ethernet.ether_type = EtherType.LLDP | 
            
                                                                                                            
                            
            
                                    
            
            
                | 86 | 1 |  |                 ethernet.source = interface.address | 
            
                                                                                                            
                            
            
                                    
            
            
                | 87 | 1 |  |                 ethernet.destination = constants.LLDP_MULTICAST_MAC | 
            
                                                                                                            
                            
            
                                    
            
            
                | 88 | 1 |  |                 ethernet.data = lldp.pack() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 89 |  |  |                 # self.vlan_id == None will result in a packet with no VLAN. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 90 | 1 |  |                 ethernet.vlans.append(VLAN(vid=self.vlan_id)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 91 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 92 | 1 |  |                 packet_out = self._build_lldp_packet_out( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 93 |  |  |                                     of_version, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 94 |  |  |                                     interface.port_number, ethernet.pack()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 95 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 96 | 1 |  |                 if packet_out is None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 97 |  |  |                     continue | 
            
                                                                                                            
                            
            
                                    
            
            
                | 98 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 99 | 1 |  |                 event_out = KytosEvent( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 100 |  |  |                     name='kytos/of_lldp.messages.out.ofpt_packet_out', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 101 |  |  |                     priority=of_msg_prio(packet_out.header.message_type.value), | 
            
                                                                                                            
                            
            
                                    
            
            
                | 102 |  |  |                     content={ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 103 |  |  |                             'destination': switch.connection, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 104 |  |  |                             'message': packet_out}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 105 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 106 | 1 |  |                 self.controller.buffers.msg_out.put(event_out) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 107 | 1 |  |                 log.debug( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 108 |  |  |                     "Sending a LLDP PacketOut to the switch %s", | 
            
                                                                                                            
                            
            
                                    
            
            
                | 109 |  |  |                     switch.dpid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 110 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 111 | 1 |  |                 msg = 'Switch: %s (%s)' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 112 | 1 |  |                 msg += ' Interface: %s' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 113 | 1 |  |                 msg += ' -- LLDP PacketOut --' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 114 | 1 |  |                 msg += ' Ethernet: eth_type (%s) | src (%s) | dst (%s) /' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 115 | 1 |  |                 msg += ' LLDP: Switch (%s) | portno (%s)' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 116 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 117 | 1 |  |                 log.debug( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 118 |  |  |                     msg, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 119 |  |  |                     switch.connection, switch.dpid, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 120 |  |  |                     interface.id, ethernet.ether_type, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 121 |  |  |                     ethernet.source, ethernet.destination, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 122 |  |  |                     switch.dpid, interface.port_number) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 123 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 124 | 1 |  |         self.try_to_publish_stopped_loops() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 125 | 1 |  |         self.liveness_manager.reaper(self.dead_interval) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 126 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 127 | 1 |  |     def load_liveness(self) -> None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 128 |  |  |         """Load liveness.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 129 | 1 |  |         interfaces = {intf.id: intf for intf in self._get_interfaces()} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 130 | 1 |  |         intfs = self.liveness_controller.get_enabled_interfaces() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 131 | 1 |  |         intfs_to_enable = [interfaces[intf["id"]] for intf in intfs] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 132 | 1 |  |         self.liveness_manager.enable(*intfs_to_enable) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 133 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 134 | 1 |  |     def try_to_publish_stopped_loops(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 135 |  |  |         """Try to publish current stopped loops.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 136 |  |  |         for dpid, port_pairs in self.loop_manager.get_stopped_loops().items(): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 137 |  |  |             try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 138 |  |  |                 switch = self.controller.get_switch_by_dpid(dpid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 139 |  |  |                 for port_pair in port_pairs: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 140 |  |  |                     interface_a = switch.interfaces[port_pair[0]] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 141 |  |  |                     interface_b = switch.interfaces[port_pair[1]] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 142 |  |  |                     self.loop_manager.publish_loop_state( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 143 |  |  |                         interface_a, interface_b, LoopState.stopped.value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 144 |  |  |                     ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 145 |  |  |             except (KeyError, AttributeError) as exc: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 146 |  |  |                 log.error("try_to_publish_stopped_loops failed with switch:" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 147 |  |  |                           f"{dpid}, port_pair: {port_pair}. {str(exc)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 148 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 149 | 1 |  |     @listen_to('kytos/topology.switch.(enabled|disabled)') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 150 | 1 |  |     def handle_lldp_flows(self, event): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 151 |  |  |         """Install or remove flows in a switch. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 152 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 153 |  |  |         Install a flow to send LLDP packets to the controller. The proactive | 
            
                                                                                                            
                            
            
                                    
            
            
                | 154 |  |  |         flow is installed whenever a switch is enabled. If the switch is | 
            
                                                                                                            
                            
            
                                    
            
            
                | 155 |  |  |         disabled the flow is removed. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 156 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 157 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 158 |  |  |             event (:class:`~kytos.core.events.KytosEvent`): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 159 |  |  |                 Event with new switch information. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 160 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 161 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 162 |  |  |         self._handle_lldp_flows(event) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 163 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 164 | 1 |  |     @listen_to("kytos/of_lldp.loop.action.log") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 165 | 1 |  |     def on_lldp_loop_log_action(self, event): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 166 |  |  |         """Handle LLDP loop log action.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 167 |  |  |         interface_a = event.content["interface_a"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 168 |  |  |         interface_b = event.content["interface_b"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 169 |  |  |         self.loop_manager.handle_log_action(interface_a, interface_b) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 170 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 171 | 1 |  |     @listen_to("kytos/of_lldp.loop.action.disable") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 172 | 1 |  |     def on_lldp_loop_disable_action(self, event): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 173 |  |  |         """Handle LLDP loop disable action.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 174 |  |  |         interface_a = event.content["interface_a"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 175 |  |  |         interface_b = event.content["interface_b"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 176 |  |  |         self.loop_manager.handle_disable_action(interface_a, interface_b) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 177 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 178 | 1 |  |     @listen_to("kytos/of_lldp.loop.detected") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 179 | 1 |  |     def on_lldp_loop_detected(self, event): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 180 |  |  |         """Handle LLDP loop detected.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 181 |  |  |         interface_id = event.content["interface_id"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 182 |  |  |         dpid = event.content["dpid"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 183 |  |  |         port_pair = event.content["port_numbers"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 184 |  |  |         self.loop_manager.handle_loop_detected(interface_id, dpid, port_pair) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 185 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 186 | 1 |  |     @listen_to("kytos/of_lldp.loop.stopped") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 187 | 1 |  |     def on_lldp_loop_stopped(self, event): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 188 |  |  |         """Handle LLDP loop stopped.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 189 |  |  |         dpid = event.content["dpid"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 190 |  |  |         port_pair = event.content["port_numbers"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 191 |  |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 192 |  |  |             switch = self.controller.get_switch_by_dpid(dpid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 193 |  |  |             interface_a = switch.interfaces[port_pair[0]] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 194 |  |  |             interface_b = switch.interfaces[port_pair[1]] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 195 |  |  |             self.loop_manager.handle_loop_stopped(interface_a, interface_b) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 196 |  |  |         except (KeyError, AttributeError) as exc: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 197 |  |  |             log.error("on_lldp_loop_stopped failed with: " | 
            
                                                                                                            
                            
            
                                    
            
            
                | 198 |  |  |                       f"{event.content} {str(exc)}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 199 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 200 | 1 |  |     @listen_to("kytos/topology.topology_loaded") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 201 | 1 |  |     def on_topology_loaded(self, event): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 202 |  |  |         """Handle on topology loaded.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 203 |  |  |         self.handle_topology_loaded(event) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 204 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 205 | 1 |  |     def handle_topology_loaded(self, event) -> None: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 206 |  |  |         """Handle on topology loaded.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 207 | 1 |  |         topology = event.content["topology"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 208 | 1 |  |         self.loop_manager.handle_topology_loaded(topology) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 209 | 1 |  |         self.load_liveness() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 210 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 211 | 1 |  |     @listen_to("kytos/topology.switches.metadata.(added|removed)") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 212 | 1 |  |     def on_switches_metadata_changed(self, event): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 213 |  |  |         """Handle on switches metadata changed.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 214 |  |  |         switch = event.content["switch"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 215 |  |  |         self.loop_manager.handle_switch_metadata_changed(switch) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 216 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 217 | 1 |  |     def _handle_lldp_flows(self, event): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 218 |  |  |         """Install or remove flows in a switch. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 219 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 220 |  |  |         Install a flow to send LLDP packets to the controller. The proactive | 
            
                                                                                                            
                            
            
                                    
            
            
                | 221 |  |  |         flow is installed whenever a switch is enabled. If the switch is | 
            
                                                                                                            
                            
            
                                    
            
            
                | 222 |  |  |         disabled the flow is removed. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 223 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 224 | 1 |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 225 | 1 |  |             dpid = event.content['dpid'] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 226 | 1 |  |             switch = self.controller.get_switch_by_dpid(dpid) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 227 | 1 |  |             of_version = switch.connection.protocol.version | 
            
                                                                                                            
                            
            
                                    
            
            
                | 228 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 229 |  |  |         except AttributeError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 230 |  |  |             of_version = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 231 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 232 | 1 |  |         def _retry_if_status_code(response, endpoint, data, status_codes, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 233 |  |  |                                   retries=3, wait=2): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 234 |  |  |             """Retry if the response is in the status_codes.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 235 | 1 |  |             if response.status_code not in status_codes: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 236 | 1 |  |                 return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 237 | 1 |  |             if retries - 1 <= 0: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 238 | 1 |  |                 return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 239 | 1 |  |             data = dict(data) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 240 | 1 |  |             data["force"] = True | 
            
                                                                                                            
                            
            
                                    
            
            
                | 241 | 1 |  |             res = requests.post(endpoint, json=data) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 242 | 1 |  |             method = res.request.method | 
            
                                                                                                            
                            
            
                                    
            
            
                | 243 | 1 |  |             if res.status_code != 202: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 244 | 1 |  |                 log.error(f"Failed to retry on {endpoint}, error: {res.text}," | 
            
                                                                                                            
                            
            
                                    
            
            
                | 245 |  |  |                           f" status: {res.status_code}, method: {method}," | 
            
                                                                                                            
                            
            
                                    
            
            
                | 246 |  |  |                           f" data: {data}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 247 | 1 |  |                 time.sleep(wait) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 248 | 1 |  |                 return _retry_if_status_code(response, endpoint, data, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 249 |  |  |                                              status_codes, retries - 1, wait) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 250 |  |  |             log.info(f"Successfully forced {method} flows to {endpoint}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 251 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 252 | 1 |  |         flow = self._build_lldp_flow(of_version, get_cookie(switch.dpid)) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 253 | 1 |  |         if flow: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 254 | 1 |  |             destination = switch.id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 255 | 1 |  |             endpoint = f'{settings.FLOW_MANAGER_URL}/flows/{destination}' | 
            
                                                                                                            
                            
            
                                    
            
            
                | 256 | 1 |  |             data = {'flows': [flow]} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 257 | 1 |  |             if event.name == 'kytos/topology.switch.enabled': | 
            
                                                                                                            
                            
            
                                    
            
            
                | 258 | 1 |  |                 flow.pop("cookie_mask") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 259 | 1 |  |                 res = requests.post(endpoint, json=data) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 260 | 1 |  |                 if res.status_code != 202: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 261 | 1 |  |                     log.error(f"Failed to push flows on {destination}," | 
            
                                                                                                            
                            
            
                                    
            
            
                | 262 |  |  |                               f" error: {res.text}, status: {res.status_code}," | 
            
                                                                                                            
                            
            
                                    
            
            
                | 263 |  |  |                               f" data: {data}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 264 | 1 |  |                 _retry_if_status_code(res, endpoint, data, [424, 500]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 265 |  |  |             else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 266 | 1 |  |                 res = requests.delete(endpoint, json=data) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 267 | 1 |  |                 if res.status_code != 202: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 268 |  |  |                     log.error(f"Failed to delete flows on {destination}," | 
            
                                                                                                            
                            
            
                                    
            
            
                | 269 |  |  |                               f" error: {res.text}, status: {res.status_code}," | 
            
                                                                                                            
                            
            
                                    
            
            
                | 270 |  |  |                               f" data: {data}") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 271 | 1 |  |                 _retry_if_status_code(res, endpoint, data, [424, 500]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 272 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 273 | 1 |  |     @alisten_to('kytos/of_core.v0x04.messages.in.ofpt_packet_in') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 274 | 1 |  |     async def on_ofpt_packet_in(self, event): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 275 |  |  |         """Dispatch two KytosEvents to notify identified NNI interfaces. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 276 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 277 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 278 |  |  |             event (:class:`~kytos.core.events.KytosEvent`): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 279 |  |  |                 Event with an LLDP packet as data. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 280 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 281 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 282 | 1 |  |         ethernet = self._unpack_non_empty(Ethernet, event.message.data) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 283 | 1 |  |         if ethernet.ether_type == EtherType.LLDP: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 284 | 1 |  |             try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 285 | 1 |  |                 lldp = self._unpack_non_empty(LLDP, ethernet.data) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 286 | 1 |  |                 dpid = self._unpack_non_empty(DPID, lldp.chassis_id.sub_value) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 287 |  |  |             except struct.error: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 288 |  |  |                 #: If we have a LLDP packet but we cannot unpack it, or the | 
            
                                                                                                            
                            
            
                                    
            
            
                | 289 |  |  |                 #: unpacked packet does not contain the dpid attribute, then | 
            
                                                                                                            
                            
            
                                    
            
            
                | 290 |  |  |                 #: we are dealing with a LLDP generated by someone else. Thus | 
            
                                                                                                            
                            
            
                                    
            
            
                | 291 |  |  |                 #: this packet is not useful for us and we may just ignore it. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 292 |  |  |                 return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 293 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 294 | 1 |  |             switch_a = event.source.switch | 
            
                                                                                                            
                            
            
                                    
            
            
                | 295 | 1 |  |             port_a = event.message.in_port | 
            
                                                                                                            
                            
            
                                    
            
            
                | 296 | 1 |  |             switch_b = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 297 | 1 |  |             port_b = None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 298 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 299 |  |  |             # in_port is currently an Int in v0x04. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 300 | 1 |  |             if isinstance(port_a, int): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 301 | 1 |  |                 port_a = UBInt32(port_a) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 302 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 303 | 1 |  |             try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 304 | 1 |  |                 switch_b = self.controller.get_switch_by_dpid(dpid.value) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 305 | 1 |  |                 port_type = UBInt32 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 306 | 1 |  |                 port_b = self._unpack_non_empty(port_type, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 307 |  |  |                                                 lldp.port_id.sub_value) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 308 |  |  |             except AttributeError: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 309 |  |  |                 log.debug("Couldn't find datapath %s.", dpid.value) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 310 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 311 |  |  |             # Return if any of the needed information are not available | 
            
                                                                                                            
                            
            
                                    
            
            
                | 312 | 1 |  |             if not (switch_a and port_a and switch_b and port_b): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 313 |  |  |                 return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 314 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 315 | 1 |  |             interface_a = switch_a.get_interface_by_port_no(port_a.value) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 316 | 1 |  |             interface_b = switch_b.get_interface_by_port_no(port_b.value) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 317 | 1 |  |             if not interface_a or not interface_b: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 318 | 1 |  |                 return | 
            
                                                                                                            
                            
            
                                    
            
            
                | 319 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 320 | 1 |  |             await self.loop_manager.process_if_looped(interface_a, interface_b) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 321 | 1 |  |             await self.liveness_manager.consume_hello_if_enabled(interface_a, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 322 |  |  |                                                                  interface_b) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 323 | 1 |  |             event_out = KytosEvent(name='kytos/of_lldp.interface.is.nni', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 324 |  |  |                                    content={'interface_a': interface_a, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 325 |  |  |                                             'interface_b': interface_b}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 326 | 1 |  |             await self.controller.buffers.app.aput(event_out) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 327 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 328 | 1 |  |     def notify_lldp_change(self, state, interface_ids): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 329 |  |  |         """Dispatch a KytosEvent to notify changes to the LLDP status.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 330 | 1 |  |         content = {'attribute': 'LLDP', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 331 |  |  |                    'state': state, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 332 |  |  |                    'interface_ids': interface_ids} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 333 | 1 |  |         event_out = KytosEvent(name='kytos/of_lldp.network_status.updated', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 334 |  |  |                                content=content) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 335 | 1 |  |         self.controller.buffers.app.put(event_out) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 336 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 337 | 1 |  |     def publish_liveness_status(self, event_suffix, interfaces): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 338 |  |  |         """Dispatch a KytosEvent to publish liveness admin status.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 339 | 1 |  |         content = {"interfaces": interfaces} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 340 | 1 |  |         name = f"kytos/of_lldp.liveness.{event_suffix}" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 341 | 1 |  |         event_out = KytosEvent(name=name, content=content) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 342 | 1 |  |         self.controller.buffers.app.put(event_out) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 343 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 344 | 1 |  |     def shutdown(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 345 |  |  |         """End of the application.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 346 |  |  |         log.debug('Shutting down...') | 
            
                                                                                                            
                            
            
                                    
            
            
                | 347 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 348 | 1 |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 349 | 1 |  |     def _build_lldp_packet_out(version, port_number, data): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 350 |  |  |         """Build a LLDP PacketOut message. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 351 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 352 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 353 |  |  |             version (int): OpenFlow version | 
            
                                                                                                            
                            
            
                                    
            
            
                | 354 |  |  |             port_number (int): Switch port number where the packet must be | 
            
                                                                                                            
                            
            
                                    
            
            
                | 355 |  |  |                 forwarded to. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 356 |  |  |             data (bytes): Binary data to be sent through the port. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 357 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 358 |  |  |         Returns: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 359 |  |  |             PacketOut message for the specific given OpenFlow version, if it | 
            
                                                                                                            
                            
            
                                    
            
            
                | 360 |  |  |                 is supported. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 361 |  |  |             None if the OpenFlow version is not supported. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 362 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 363 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 364 | 1 |  |         if version == 0x04: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 365 | 1 |  |             action_output_class = AO13 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 366 | 1 |  |             packet_out_class = PO13 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 367 |  |  |         else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 368 | 1 |  |             log.info('Openflow version %s is not yet supported.', version) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 369 | 1 |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 370 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 371 | 1 |  |         output_action = action_output_class() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 372 | 1 |  |         output_action.port = port_number | 
            
                                                                                                            
                            
            
                                    
            
            
                | 373 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 374 | 1 |  |         packet_out = packet_out_class() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 375 | 1 |  |         packet_out.data = data | 
            
                                                                                                            
                            
            
                                    
            
            
                | 376 | 1 |  |         packet_out.actions.append(output_action) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 377 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 378 | 1 |  |         return packet_out | 
            
                                                                                                            
                            
            
                                    
            
            
                | 379 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 380 | 1 |  |     def _build_lldp_flow(self, version, cookie, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 381 |  |  |                          cookie_mask=0xffffffffffffffff): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 382 |  |  |         """Build a Flow message to send LLDP to the controller. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 383 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 384 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 385 |  |  |             version (int): OpenFlow version. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 386 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 387 |  |  |         Returns: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 388 |  |  |             Flow dictionary message for the specific given OpenFlow version, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 389 |  |  |             if it is supported. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 390 |  |  |             None if the OpenFlow version is not supported. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 391 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 392 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 393 | 1 |  |         flow = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 394 | 1 |  |         if version == 0x04: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 395 | 1 |  |             flow['actions'] = [{'action_type': 'output', | 
            
                                                                                                            
                            
            
                                    
            
            
                | 396 |  |  |                                 'port': Port13.OFPP_CONTROLLER}] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 397 |  |  |         else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 398 | 1 |  |             return None | 
            
                                                                                                            
                            
            
                                    
            
            
                | 399 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 400 | 1 |  |         match = {} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 401 | 1 |  |         self.set_flow_table_group_owner(flow) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 402 | 1 |  |         flow['priority'] = settings.FLOW_PRIORITY | 
            
                                                                                                            
                            
            
                                    
            
            
                | 403 | 1 |  |         flow['table_id'] = settings.TABLE_ID | 
            
                                                                                                            
                            
            
                                    
            
            
                | 404 | 1 |  |         flow['cookie'] = cookie | 
            
                                                                                                            
                            
            
                                    
            
            
                | 405 | 1 |  |         flow['cookie_mask'] = cookie_mask | 
            
                                                                                                            
                            
            
                                    
            
            
                | 406 | 1 |  |         match['dl_type'] = EtherType.LLDP | 
            
                                                                                                            
                            
            
                                    
            
            
                | 407 | 1 |  |         if self.vlan_id: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 408 | 1 |  |             match['dl_vlan'] = self.vlan_id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 409 | 1 |  |         flow['match'] = match | 
            
                                                                                                            
                            
            
                                    
            
            
                | 410 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 411 | 1 |  |         return flow | 
            
                                                                                                            
                            
            
                                    
            
            
                | 412 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 413 | 1 |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 414 | 1 |  |     def _unpack_non_empty(desired_class, data): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 415 |  |  |         """Unpack data using an instance of desired_class. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 416 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 417 |  |  |         Args: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 418 |  |  |             desired_class (class): The class to be used to unpack data. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 419 |  |  |             data (bytes): bytes to be unpacked. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 420 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 421 |  |  |         Return: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 422 |  |  |             An instance of desired_class class with data unpacked into it. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 423 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 424 |  |  |         Raises: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 425 |  |  |             UnpackException if the unpack could not be performed. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 426 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 427 |  |  |         """ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 428 | 1 |  |         obj = desired_class() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 429 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 430 | 1 |  |         if hasattr(data, 'value'): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 431 | 1 |  |             data = data.value | 
            
                                                                                                            
                            
            
                                    
            
            
                | 432 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 433 | 1 |  |         obj.unpack(data) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 434 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 435 | 1 |  |         return obj | 
            
                                                                                                            
                            
            
                                    
            
            
                | 436 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 437 | 1 |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 438 | 1 |  |     def _get_data(req): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 439 |  |  |         """Get request data.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 440 | 1 |  |         data = req.get_json()  # Valid format { "interfaces": [...] } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 441 | 1 |  |         return data.get('interfaces', []) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 442 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 443 | 1 |  |     def _get_interfaces(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 444 |  |  |         """Get all interfaces.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 445 | 1 |  |         interfaces = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 446 | 1 |  |         for switch in list(self.controller.switches.values()): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 447 | 1 |  |             interfaces += list(switch.interfaces.values()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 448 | 1 |  |         return interfaces | 
            
                                                                                                            
                            
            
                                    
            
            
                | 449 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 450 | 1 |  |     @staticmethod | 
            
                                                                                                            
                            
            
                                    
            
            
                | 451 | 1 |  |     def _get_interfaces_dict(interfaces): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 452 |  |  |         """Return a dict of interfaces.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 453 | 1 |  |         return {inter.id: inter for inter in interfaces} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 454 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 455 | 1 |  |     def _get_lldp_interfaces(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 456 |  |  |         """Get interfaces enabled to receive LLDP packets.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 457 | 1 |  |         return [inter.id for inter in self._get_interfaces() if inter.lldp] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 458 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 459 | 1 |  |     @rest('v1/interfaces', methods=['GET']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 460 | 1 |  |     def get_lldp_interfaces(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 461 |  |  |         """Return all the interfaces that have LLDP traffic enabled.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 462 | 1 |  |         return jsonify({"interfaces": self._get_lldp_interfaces()}), 200 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 463 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 464 | 1 |  |     @rest('v1/interfaces/disable', methods=['POST']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 465 | 1 |  |     def disable_lldp(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 466 |  |  |         """Disables an interface to receive LLDP packets.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 467 | 1 |  |         interface_ids = self._get_data(request) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 468 | 1 |  |         error_list = []  # List of interfaces that were not activated. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 469 | 1 |  |         changed_interfaces = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 470 | 1 |  |         interface_ids = filter(None, interface_ids) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 471 | 1 |  |         interfaces = self._get_interfaces() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 472 | 1 |  |         intfs = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 473 | 1 |  |         if not interfaces: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 474 | 1 |  |             return jsonify("No interfaces were found."), 404 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 475 | 1 |  |         interfaces = self._get_interfaces_dict(interfaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 476 | 1 |  |         for id_ in interface_ids: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 477 | 1 |  |             interface = interfaces.get(id_) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 478 | 1 |  |             if interface: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 479 | 1 |  |                 interface.lldp = False | 
            
                                                                                                            
                            
            
                                    
            
            
                | 480 | 1 |  |                 changed_interfaces.append(id_) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 481 | 1 |  |                 intfs.append(interface) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 482 |  |  |             else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 483 | 1 |  |                 error_list.append(id_) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 484 | 1 |  |         if changed_interfaces: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 485 | 1 |  |             self.notify_lldp_change('disabled', changed_interfaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 486 | 1 |  |             intf_ids = [intf.id for intf in intfs] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 487 | 1 |  |             self.liveness_controller.disable_interfaces(intf_ids) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 488 | 1 |  |             self.liveness_manager.disable(*intfs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 489 | 1 |  |             self.publish_liveness_status("disabled", intfs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 490 | 1 |  |         if not error_list: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 491 | 1 |  |             return jsonify( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 492 |  |  |                 "All the requested interfaces have been disabled."), 200 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 493 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 494 |  |  |         # Return a list of interfaces that couldn't be disabled | 
            
                                                                                                            
                            
            
                                    
            
            
                | 495 | 1 |  |         msg_error = "Some interfaces couldn't be found and deactivated: " | 
            
                                                                                                            
                            
            
                                    
            
            
                | 496 | 1 |  |         return jsonify({msg_error: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 497 |  |  |                         error_list}), 400 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 498 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 499 | 1 |  |     @rest('v1/interfaces/enable', methods=['POST']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 500 | 1 |  |     def enable_lldp(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 501 |  |  |         """Enable an interface to receive LLDP packets.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 502 | 1 |  |         interface_ids = self._get_data(request) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 503 | 1 |  |         error_list = []  # List of interfaces that were not activated. | 
            
                                                                                                            
                            
            
                                    
            
            
                | 504 | 1 |  |         changed_interfaces = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 505 | 1 |  |         interface_ids = filter(None, interface_ids) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 506 | 1 |  |         interfaces = self._get_interfaces() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 507 | 1 |  |         if not interfaces: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 508 | 1 |  |             return jsonify("No interfaces were found."), 404 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 509 | 1 |  |         interfaces = self._get_interfaces_dict(interfaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 510 | 1 |  |         for id_ in interface_ids: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 511 | 1 |  |             interface = interfaces.get(id_) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 512 | 1 |  |             if interface: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 513 | 1 |  |                 interface.lldp = True | 
            
                                                                                                            
                            
            
                                    
            
            
                | 514 | 1 |  |                 changed_interfaces.append(id_) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 515 |  |  |             else: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 516 | 1 |  |                 error_list.append(id_) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 517 | 1 |  |         if changed_interfaces: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 518 | 1 |  |             self.notify_lldp_change('enabled', changed_interfaces) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 519 | 1 |  |         if not error_list: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 520 | 1 |  |             return jsonify( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 521 |  |  |                 "All the requested interfaces have been enabled."), 200 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 522 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 523 |  |  |         # Return a list of interfaces that couldn't be enabled | 
            
                                                                                                            
                            
            
                                    
            
            
                | 524 | 1 |  |         msg_error = "Some interfaces couldn't be found and activated: " | 
            
                                                                                                            
                            
            
                                    
            
            
                | 525 | 1 |  |         return jsonify({msg_error: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 526 |  |  |                         error_list}), 400 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 527 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 528 | 1 |  |     @rest("v1/liveness/enable", methods=["POST"]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 529 | 1 |  |     def enable_liveness(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 530 |  |  |         """Enable liveness link detection on interfaces.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 531 | 1 |  |         intf_ids = self._get_data(request) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 532 | 1 |  |         if not intf_ids: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 533 |  |  |             return jsonify("Interfaces payload is empty"), 400 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 534 | 1 |  |         interfaces = {intf.id: intf for intf in self._get_interfaces()} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 535 | 1 |  |         diff = set(intf_ids) - set(interfaces.keys()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 536 | 1 |  |         if diff: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 537 |  |  |             return jsonify(f"Interface IDs {diff} not found"), 404 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 538 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 539 | 1 |  |         intfs = [interfaces[_id] for _id in intf_ids] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 540 | 1 |  |         non_lldp = [intf.id for intf in intfs if not intf.lldp] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 541 | 1 |  |         if non_lldp: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 542 |  |  |             msg = f"Interface IDs {non_lldp} don't have LLDP enabled" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 543 |  |  |             return jsonify(msg), 400 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 544 | 1 |  |         self.liveness_controller.enable_interfaces(intf_ids) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 545 | 1 |  |         self.liveness_manager.enable(*intfs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 546 | 1 |  |         self.publish_liveness_status("enabled", intfs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 547 | 1 |  |         return jsonify(), 200 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 548 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 549 | 1 |  |     @rest("v1/liveness/disable", methods=["POST"]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 550 | 1 |  |     def disable_liveness(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 551 |  |  |         """Disable liveness link detection on interfaces.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 552 | 1 |  |         intf_ids = self._get_data(request) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 553 | 1 |  |         if not intf_ids: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 554 |  |  |             return jsonify("Interfaces payload is empty"), 400 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 555 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 556 | 1 |  |         interfaces = {intf.id: intf for intf in self._get_interfaces()} | 
            
                                                                                                            
                            
            
                                    
            
            
                | 557 | 1 |  |         diff = set(intf_ids) - set(interfaces.keys()) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 558 | 1 |  |         if diff: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 559 |  |  |             return jsonify(f"Interface IDs {diff} not found"), 404 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 560 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 561 | 1 |  |         intfs = [interfaces[_id] for _id in intf_ids if _id in interfaces] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 562 | 1 |  |         self.liveness_controller.disable_interfaces(intf_ids) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 563 | 1 |  |         self.liveness_manager.disable(*intfs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 564 | 1 |  |         self.publish_liveness_status("disabled", intfs) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 565 | 1 |  |         return jsonify(), 200 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 566 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 567 | 1 |  |     @rest("v1/liveness/", methods=["GET"]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 568 | 1 |  |     def get_liveness_interfaces(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 569 |  |  |         """Get liveness interfaces.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 570 | 1 |  |         args = request.args | 
            
                                                                                                            
                            
            
                                    
            
            
                | 571 | 1 |  |         interface_id = args.get("interface_id") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 572 | 1 |  |         if interface_id: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 573 |  |  |             status, last_hello_at = self.liveness_manager.get_interface_status( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 574 |  |  |                 interface_id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 575 |  |  |             ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 576 |  |  |             if not status: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 577 |  |  |                 return {"interfaces": []}, 200 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 578 |  |  |             body = { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 579 |  |  |                 "interfaces": [ | 
            
                                                                                                            
                            
            
                                    
            
            
                | 580 |  |  |                     { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 581 |  |  |                         "id": interface_id, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 582 |  |  |                         "status": status, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 583 |  |  |                         "last_hello_at": last_hello_at, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 584 |  |  |                     } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 585 |  |  |                 ] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 586 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 587 |  |  |             return jsonify(body), 200 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 588 | 1 |  |         interfaces = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 589 | 1 |  |         for interface_id in list(self.liveness_manager.interfaces.keys()): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 590 |  |  |             status, last_hello_at = self.liveness_manager.get_interface_status( | 
            
                                                                                                            
                            
            
                                    
            
            
                | 591 |  |  |                 interface_id | 
            
                                                                                                            
                            
            
                                    
            
            
                | 592 |  |  |             ) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 593 |  |  |             interfaces.append({"id": interface_id, "status": status, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 594 |  |  |                               "last_hello_at": last_hello_at}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 595 | 1 |  |         return jsonify({"interfaces": interfaces}), 200 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 596 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 597 | 1 |  |     @rest("v1/liveness/pair", methods=["GET"]) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 598 | 1 |  |     def get_liveness_interface_pairs(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 599 |  |  |         """Get liveness interface pairs.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 600 | 1 |  |         pairs = [] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 601 | 1 |  |         for entry in list(self.liveness_manager.liveness.values()): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 602 |  |  |             lsm = entry["lsm"] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 603 |  |  |             pair = { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 604 |  |  |                 "interface_a": { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 605 |  |  |                     "id": entry["interface_a"].id, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 606 |  |  |                     "status": lsm.ilsm_a.state, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 607 |  |  |                     "last_hello_at": lsm.ilsm_a.last_hello_at, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 608 |  |  |                 }, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 609 |  |  |                 "interface_b": { | 
            
                                                                                                            
                            
            
                                    
            
            
                | 610 |  |  |                     "id": entry["interface_b"].id, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 611 |  |  |                     "status": lsm.ilsm_b.state, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 612 |  |  |                     "last_hello_at": lsm.ilsm_b.last_hello_at, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 613 |  |  |                 }, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 614 |  |  |                 "status": lsm.state | 
            
                                                                                                            
                            
            
                                    
            
            
                | 615 |  |  |             } | 
            
                                                                                                            
                            
            
                                    
            
            
                | 616 |  |  |             pairs.append(pair) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 617 | 1 |  |         return jsonify({"pairs": pairs}) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 618 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 619 | 1 |  |     @rest('v1/polling_time', methods=['GET']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 620 | 1 |  |     def get_time(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 621 |  |  |         """Get LLDP polling time in seconds.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 622 | 1 |  |         return jsonify({"polling_time": self.polling_time}), 200 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 623 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 624 | 1 |  |     @rest('v1/polling_time', methods=['POST']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 625 | 1 |  |     def set_time(self): | 
            
                                                                                                            
                            
            
                                    
            
            
                | 626 |  |  |         """Set LLDP polling time.""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 627 |  |  |         # pylint: disable=attribute-defined-outside-init | 
            
                                                                                                            
                            
            
                                    
            
            
                | 628 | 1 |  |         try: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 629 | 1 |  |             payload = request.get_json() | 
            
                                                                                                            
                            
            
                                    
            
            
                | 630 | 1 |  |             polling_time = int(payload['polling_time']) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 631 | 1 |  |             if polling_time <= 0: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 632 |  |  |                 raise ValueError(f"invalid polling_time {polling_time}, " | 
            
                                                                                                            
                            
            
                                    
            
            
                | 633 |  |  |                                  "must be greater than zero") | 
            
                                                                                                            
                            
            
                                    
            
            
                | 634 | 1 |  |             self.polling_time = polling_time | 
            
                                                                                                            
                            
            
                                    
            
            
                | 635 | 1 |  |             self.execute_as_loop(self.polling_time) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 636 | 1 |  |             log.info("Polling time has been updated to %s" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 637 |  |  |                      " second(s), but this change will not be saved" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 638 |  |  |                      " permanently.", self.polling_time) | 
            
                                                                                                            
                            
            
                                    
            
            
                | 639 | 1 |  |             return jsonify("Polling time has been updated."), 200 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 640 | 1 |  |         except (ValueError, KeyError) as error: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 641 | 1 |  |             msg = f"This operation is not completed: {error}" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 642 | 1 |  |             return jsonify(msg), 400 | 
            
                                                                                                            
                            
            
                                    
            
            
                | 643 |  |  |  | 
            
                                                                                                            
                            
            
                                    
            
            
                | 644 | 1 |  |     def set_flow_table_group_owner(self, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 645 |  |  |                                    flow: dict, | 
            
                                                                                                            
                            
            
                                    
            
            
                | 646 |  |  |                                    group: str = "base") -> dict: | 
            
                                                                                                            
                            
            
                                    
            
            
                | 647 |  |  |         """Set owner, table_group and table_id""" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 648 | 1 |  |         flow["table_id"] = self.table_group[group] | 
            
                                                                                                            
                            
            
                                    
            
            
                | 649 | 1 |  |         flow["owner"] = "of_lldp" | 
            
                                                                                                            
                            
            
                                    
            
            
                | 650 | 1 |  |         flow["table_group"] = group | 
            
                                                                                                            
                            
            
                                    
            
            
                | 651 | 1 |  |         return flow | 
            
                                                                                                            
                            
            
                                    
            
            
                | 652 |  |  |  | 
            
                                                                                                            
                                                                
            
                                    
            
            
                | 653 |  |  |     # pylint: disable=attribute-defined-outside-init | 
            
                                                        
            
                                    
            
            
                | 654 | 1 |  |     @alisten_to("kytos/of_multi_table.enable_table") | 
            
                                                        
            
                                    
            
            
                | 655 | 1 |  |     async def on_table_enabled(self, event): | 
            
                                                        
            
                                    
            
            
                | 656 |  |  |         """Handle a recently table enabled. | 
            
                                                        
            
                                    
            
            
                | 657 |  |  |         of_lldp only allows "base" as flow group | 
            
                                                        
            
                                    
            
            
                | 658 |  |  |         """ | 
            
                                                        
            
                                    
            
            
                | 659 | 1 |  |         table_group = event.content.get("of_lldp", None) | 
            
                                                        
            
                                    
            
            
                | 660 | 1 |  |         if not table_group: | 
            
                                                        
            
                                    
            
            
                | 661 |  |  |             return | 
            
                                                        
            
                                    
            
            
                | 662 | 1 |  |         for group in table_group: | 
            
                                                        
            
                                    
            
            
                | 663 | 1 |  |             if group not in settings.TABLE_GROUP_ALLOWED: | 
            
                                                        
            
                                    
            
            
                | 664 | 1 |  |                 log.error(f'The table group "{group}" is not allowed for ' | 
            
                                                        
            
                                    
            
            
                | 665 |  |  |                           f'of_lldp. Allowed table groups are ' | 
            
                                                        
            
                                    
            
            
                | 666 |  |  |                           f'{settings.TABLE_GROUP_ALLOWED}') | 
            
                                                        
            
                                    
            
            
                | 667 | 1 |  |                 return | 
            
                                                        
            
                                    
            
            
                | 668 | 1 |  |         self.table_group = table_group | 
            
                                                        
            
                                    
            
            
                | 669 | 1 |  |         content = {"group_table": self.table_group} | 
            
                                                        
            
                                    
            
            
                | 670 | 1 |  |         event_out = KytosEvent(name="kytos/of_lldp.enable_table", | 
            
                                                        
            
                                    
            
            
                | 671 |  |  |                                content=content) | 
            
                                                        
            
                                    
            
            
                | 672 |  |  |         await self.controller.buffers.app.aput(event_out) | 
            
                                                        
            
                                    
            
            
                | 673 |  |  |  |