def setupProtection(self, data=None): self.data = data Log.info("Setup port protection") dt = DevTarget_t(0, hex_to_i16(0xFFFF)) p = port_down_packet() pktlen = self.port_pkt_len = len(p) self.tc.conn_mgr.pktgen_write_pkt_buffer(self.tc.hdl, dt, 0, pktlen, str(p)) offset = 0 # enable on all pipes for pipe in range(0, self.pal.pal_num_pipes_get(0)): port = (pipe << 7 | 68) self.tc.conn_mgr.pktgen_enable(self.tc.hdl, 0, (pipe << 7 | 68)) Log.debug("Enable pkt gen on port", port) config = PktGenAppCfg_t(trigger_type=PktGenTriggerType_t.PORT_DOWN, timer=0, src_port=68, buffer_offset=offset, length=pktlen) self.tc.conn_mgr.pktgen_cfg_app(self.tc.hdl, dt, 0, config) self.tc.conn_mgr.pktgen_app_enable(self.tc.hdl, dt, 0) offset=pktlen
def purge(self): """ Delete all current table entries """ [self.delete_table_entry(table_name=e[0], entry=e[1]) for e in self.entries] Log.info("Entries purged") self.entries = []
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 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 init_flood_group(self): """ This method initializes the multicast group that is responsible for flooding """ p = Popen([self.cli, '--thrift-port', str(self.thrift_port)], stdout=PIPE, stdin=PIPE, stderr=STDOUT) # multicast group 1 is flood group out, err = p.communicate(input="mc_mgrp_create 1") if err: Log.error(err) p = Popen([self.cli, '--thrift-port', str(self.thrift_port)], stdout=PIPE, stdin=PIPE, stderr=STDOUT) out, err = p.communicate(input="mc_node_associate 1 0") if err: Log.error(err) Log.info("Initialize flood group")
def main(): # without this line, no events would be fired, no topology discovered and no entries computed Event.activate() # base controller controller = BaseController(p4info_file_path=Configuration.get('p4info'), bmv2_path=Configuration.get('bmv2_json'), prog_name=Configuration.get('prog_name'), bin_path=Configuration.get('bin_path'), cxt_json_path=Configuration.get('cxt_path')) # register event for new switch connections, this will add switches to device list Event.on('new_switch_connection', TopologyManager.add_device) # register events for static classes Event.on("packet_in", MessageInHandler.message_in) # handles generic packet in Event.on("topology_to_controller", GlobalConnection.send_topology_packet ) # triggers the send routine to server Event.on("igmp_packet_to_controller", GlobalConnection.send_group_packet ) # triggers the send routine to server Event.on( "port_msg_to_controller", GlobalConnection.send_port_info) # triggers the send routine to server topology = TopologyController(controller) # Create instances of sub controller mac = MacController(controller) port = PortController(controller=controller) pd = PDSetup() mc = MulticastController(pd=pd, base=controller) # start connection procedure init_switches(controller=controller, topology_controller=topology, pd=pd) bier = BierController(controller) # start grpc server for connection to main controller grpc_server = GRPCServer(listen_port=Configuration.get('listen_port')) # set controller in local server for table entry LocalServer.controller = controller # start grpc server grpc_server.start() # start port monitor #threading.Thread(target=port.monitor_messages()).start() try: while True: time.sleep(1) except KeyboardInterrupt: pd.end() Log.info("Shutting down") os._exit(0)
def start(self): """ Start grpc server This grpc server will be used for the direction global-controller ----> local-controller """ proto.connection_pb2_grpc.add_LocalServerServicer_to_server(LocalServer(), self.server) self.server.add_insecure_port('0.0.0.0:' + str(self.listen_port)) Log.info("Start GRPC Server on port", self.listen_port) self.server.start()
def __init__(self, ip=None, port=0): self.channel = grpc.insecure_channel(ip + ":" + str(port)) self.stub = proto.connection_pb2_grpc.GlobalServerStub(self.channel) reponse = self.stub.CheckConnection(proto.connection_pb2.Empty()) Log.info("Global connection to", ip + ":" + str(port)) # remove possible old connection when a new global connection is initialized Event.on('global_connection', self.close)
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 delete_table_entry(self, table_name=None, entry=None): """ Deletes an table entry on the switch :param table_name: table name :param entry: table entry :return: """ try: table_entry = self.__p4info_helper.buildTableEntry( table_name=table_name, match_fields=entry.match_fields, priority=entry.priority) self.__connection.DeleteTableEntry(table_entry) Log.info("Remove entry:", table_name, entry.match_fields) return True except Exception as e: Log.error("Error in table delete", table_name, entry.match_fields, entry.priority, e) return False
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 add_table_entry(self, table_name=None, entry=None): """ Adds an table entry and locks write request to prevent threading problems :param table_name: table name :param entry: Table entry :return: """ try: table_entry = self.__p4info_helper.buildTableEntry( table_name=table_name, match_fields=entry.match_fields, action_name=entry.action_name, action_params=entry.action_params, priority=entry.priority) self.__connection.WriteTableEntry(table_entry) Log.info("Add entry:", table_name, entry) return True except Exception as e: Log.error(e, "for", table_name, entry.match_fields, entry.action_name, entry.action_params, entry.priority) return False
def setMirrorSession(self, config_file=None): Log.info("Set mirror session") self.mirror.setMirrorSession(Configuration.load(config_file))
def close(self): Log.info("Global connection removed") Event.off('global_connection', self.close) self.channel.close()
def setPorts(self, config_file=None): Log.info("Set ports") self.pc.setPorts(Configuration.load(config_file))
def end(self): Log.info("Close pd connection") self.mc.end() self.tc.end()
def configureTopologyPackets(self, config_file=None): Log.info("Configure topology packets") self.pm.configureTopologyPackets()
def setPortMonitor(self, config_file=None): Log.info("Set port monitor") self.pm.setupProtection(Configuration.load(config_file))
def setFlood(self, config_file=None): Log.info("Set flood mc group") self.mc.setFlood(Configuration.load(config_file))