def monitor_messages(self): """ Wait for port status message """ Log.info("Start port monitor") while True: msg = self.sub.recv() msg_type = struct.unpack('4s', msg[:4]) if msg_type[0] == 'PRT|': switch_id = struct.unpack('Q', msg[4:12]) num_statuses = struct.unpack('I', msg[16:20]) # wir betrachten immer nur den ersten Status port, status = struct.unpack('ii', msg[32:40]) self.port_status[port] = status if status == 0: # save port status time # timestamp type, type 2 is port info Log.log_to_file(round((time.time() * 1000) % 1000000), 2, "\r\n", file="logs/port_info.txt") device = TopologyManager.get_device(Configuration.get('name')) device.remove_port(port=port) Event.trigger("topology_change") bool_stat = (status == 1) Event.trigger("port_msg_to_controller", info=proto.connection_pb2.PortInfo(switch=Configuration.get('name'), port=port, status=bool_stat))
def handle_topology_answer(self, pkt=None): """ Handle topology packet :param pkt: contains the topology packet :return: """ # if the controller is not yet connected to all local controllers # don't handle topology packets if not Configuration.get('system_done'): return ip = pkt.ip.encode('utf-8') mac = pkt.mac.encode('utf-8') name = pkt.name.encode('utf-8') port = pkt.port switch = pkt.switch.encode('utf-8') if name.startswith('h'): # it's a host TopologyManager.add_device(name=name, device=Host(name=name, ip=ip, mac=mac)) TopologyManager.get_device(name=name).add_device_to_port( device=switch, port=1) Log.event("topology packet with identifier", name, "from switch", switch, "on port", port, "with ip", ip) if TopologyManager.get_device(name=switch).add_device_to_port( device=name, port=int(port)): Event.trigger("topology_change", src_device=switch, dst_device=name, port=int(port))
def message_in(*args, **kwargs): """ Generic message_in handle function Triggers corresponding event :param kwargs: :return: """ packet = kwargs.get('packet') switch = kwargs.get('switch') try: pkt = Ether(packet.packet.payload) try: Configuration.get('system_done') except ConfigurationNotFound: return if pkt.type == 0xDD00: # its an topology packet Event.trigger("topology_packet_in", packet=pkt, switch=switch) if pkt.type == 0x800: # its an igmp packet igmp = pkt.payload.payload pkt = proto.connection_pb2.GroupPacket( type=int(igmp.type), mc_address=str(igmp.gaddr), src_ip=str(pkt.payload.src), switch=Configuration.get('name')) Event.trigger("igmp_packet_to_controller", pkt=pkt) except Exception as e: # it's not an ethernet frame pass
def stream_recv(self, stream): try: for p in stream: self.stream_in_q.put(p) Event.trigger("packet_in", packet=p, switch=self.name) except grpc.RpcError as e: pass # arbitration end
def Hello(self, request, context): Event.trigger('global_connection') GlobalConnection.global_connection = GlobalConnection(ip=request.ip, port=request.port) device = TopologyManager.get_device(Configuration.get('name')) return proto.connection_pb2.SwitchInfo(name=Configuration.get('name'), ip=device.get_ip(), mac=device.get_mac(), bfr_id=device.get_bfr_id(0))
def updatePorts(self, pkt=None): port = pkt[PortDown].port_num device = TopologyManager.get_device(Configuration.get('name')) device.remove_port(port=port) Event.trigger("topology_change") Event.trigger("port_msg_to_controller", info=proto.connection_pb2.PortInfo( switch=Configuration.get('name'), port=port, status=False))
def set_forwarding_pipeline_config(self): """ Set forwarding pipeline on the switch based on p4info file :return: """ try: self.__connection.SetForwardingPipelineConfig(p4info=self.__p4info_helper.p4info, prog_name=self.prog_name, bin_path=self.bin_path, cxt_json_path=self.cxt_json_path) Event.trigger("switch_arbitrated") except Exception as e: Log.error("Error in forwarding pipeline", e) Log.info("Forwarding pipeline set.")
def set_forwarding_pipeline_config(self): """ Set forwarding pipeline on the switch based on p4info file :return: """ try: self.__connection.SetForwardingPipelineConfig(p4info=self.__p4info_helper.p4info, bmv2_json_file_path=self.__bmv2_file_path.encode()) Event.trigger("switch_arbitrated") except Exception as e: Log.error("Error in forwarding pipeline", e) Log.info("Forwarding pipeline set.")
def PortMessage(self, request, context): """ This method receives a port message """ Log.async_info("Got port message") Log.async_debug(request) # this event is not catched yet # for demonstration purpose, the topology doesn't get updated # on a link failure Event.trigger("port_message", message=request) return proto.connection_pb2.Status(code=1, message="Accepted")
def handle_packet_in(pkt): switch = pkt.switch.encode('utf-8') mc_addr = pkt.mc_address.encode('utf-8') src_ip = pkt.src_ip.encode('utf-8') if pkt.type == 0x16: GroupManager.add_to_group(switch, src_ip, mc_addr) elif pkt.type == 0x17: GroupManager.remove_from_group(switch, src_ip, mc_addr) Event.trigger("group_update") Log.event("Got igmp packet with type", hex(pkt.type), "and src", src_ip, "for group", mc_addr, "from", switch)
def show_all(): """ Show current configuration :return: """ data = PrettyTable() data.field_names = ["Name", "Value"] for key, value in Configuration.settings.iteritems(): if key == "switches": value = "Switch-Array - Omitted due to length" data.add_row([key, value]) Event.trigger('log_to_input', str=(str(data)))
def __init__(self, grpc_address=None): self.channel = grpc.insecure_channel(grpc_address) self.stub = proto.connection_pb2_grpc.LocalServerStub(self.channel) response = self.stub.Hello( proto.connection_pb2.HelloMessage( ip="127.0.0.1", port=int(Configuration.get('listen_port')))) self.name = response.name.encode('utf-8') Event.trigger('new_switch_connection', name=self.name, device=Switch(name=self.name, ip=response.ip.encode('utf-8'), mac=response.mac.encode('utf-8'), bfr_id=response.bfr_id))
def connect(self): """ All switches grpc addresses are in ascending order. Connect until a connection can't be established :return: """ for switch in Configuration.get("switches"): try: self.__connections[switch["name"]] = SwitchConnection( grpc_address='127.0.0.1:{0}'.format( switch["local_controller_port"])) Log.async_debug("Connected to controller on port", switch["local_controller_port"]) Event.trigger('switch_connected', name=switch["name"]) except grpc.RpcError as e: raise SwitchConnectionFailed(switch["name"], switch["local_controller_port"]) Log.async_info("Connected to", len(self.__connections), "controller") Configuration.set('connected', True)
def handle_topology_answer(self, *args, **kwargs): """ Handle topology packet :param args: contains the topology packet :return: """ packet = kwargs.get('packet') switch = kwargs.get('switch') pkt = packet pkt = packet.payload Event.trigger("clear_port_down", port=int(pkt.port)) if pkt.device_type != 1: name = "s" + str(pkt.identifier) TopologyManager.add_device(name=name, device=Host(name=name, ip=pkt.ip, mac=pkt.mac)) else: # its a host name = "h" + str(pkt.identifier) TopologyManager.add_device(name=name, device=Host(name=name, ip=pkt.ip, mac=pkt.mac)) if TopologyManager.get_device(name=switch).add_device_to_port(device=name, port=int(pkt.port)): Event.trigger("topology_change", src_device=switch, dst_device=name, port=int(pkt.port)) #Log.info("Pkt in:", pkt.port) topology_packet = proto.connection_pb2.TopologyPacket(ip=pkt.ip, mac=pkt.mac, port=pkt.port, name=name, switch=Configuration.get('name')) Event.trigger("topology_to_controller", pkt=topology_packet)
def message_in(*args, **kwargs): """ Generic message_in handle function Triggers corresponding event :param kwargs: :return: """ packet = kwargs.get('packet') switch = kwargs.get('switch') try: pkt = Ether(packet.packet.payload) try: Configuration.get('system_done') except ConfigurationNotFound: return if pkt.type == 0xEE00: # its an port down packet Log.info("Port:", pkt[PortDown].port_num, "down", "on ingress", pkt[PortDown].pad1, "on pipe") Event.trigger("port_down", pkt=pkt) if pkt.type == 0xDD00: # its an topology packet Event.trigger("topology_packet_in", packet=pkt, switch=switch) if pkt.type == 0x800 and pkt[IP].proto == 2: # its an igmp packet igmp = pkt.payload pkt = proto.connection_pb2.GroupPacket(type=int(igmp.type), mc_address=str(igmp.gaddr), src_ip=str(igmp.src), switch=Configuration.get('name')) Event.trigger("igmp_packet_to_controller", pkt=pkt) Log.debug("Send igmp packet to controller") except Exception as e: # it's not an ethernet frame pass
def connect_and_arbitrate(self, grpc_port=0, device_id=0): """ Connect and arbitrate to the switch :param grpc_port: grpc port of the p4 switch :param device_id: device id of the p4 switch :return: """ i = Configuration.get('bfr_id') try: # add connection to switch self.__connection = self.__add_switch_connection(name='s{0}'.format(i), address='127.0.0.1:{0}'.format(grpc_port), device_id=device_id) # start packet in thread self.__connection.start_thread() if self.__connection.MasterArbitrationUpdate(): base_mac = int('20:00:00:00:00:00'.translate(None, ":,-"), 16) real_mac = format(base_mac + i, 'x') mac = ":".join(real_mac[i:i + 2] for i in range(0, len(real_mac), 2)) Configuration.set('name', 's{0}'.format(i).encode('utf-8')) Event.trigger("new_switch_connection", name='s{0}'.format(i), device=Switch(name='s{0}'.format(i).encode('utf-8'), ip='20.0.{0}.0'.format(i).encode('utf-8'), mac=mac.encode('utf-8'), bfr_id=i)) Log.info("Arbitration done. Connected to swtich") Event.trigger("arbitration_done") else: Log.error("Master arbitration failed") except Exception as e: Log.error(e)
def TopologyMessage(self, request, context): Event.trigger("topology_packet_in", pkt=request) return proto.connection_pb2.Status(code=1, message="accepted")
def echo(msg): Event.trigger('log_to_input', str=(str(msg)))
def async_debug(*args): if Configuration.get("debug"): Event.trigger('log_to_output', str=('[D]' + ' ' + ' '.join(map(str, args))))
def async_info(*args): Event.trigger('log_to_output', str=('[I]' + ' ' + ' '.join(map(str, args))))
def _(event): " Pressing Ctrl-Q or Ctrl-C will exit the user interface. " Event.trigger('exit') event.app.exit()