Ejemplo n.º 1
0
    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))
Ejemplo n.º 2
0
    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))
Ejemplo n.º 3
0
    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
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    def __init__(self, base):
        self._baseController = base
        Event.on("topology_change",
                 self.update)  # update bier tables when topology changes

        # this controller manages the following tables
        self.table_manager = TableEntryManager(controller=base,
                                               name="BierController")
        self.table_manager.init_table("ingress.bier_c.bift")
Ejemplo n.º 6
0
    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)
Ejemplo n.º 7
0
    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))
Ejemplo n.º 8
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))
Ejemplo n.º 9
0
    def __init__(self, base):
        """
        Init Maccontroller with base controller
        :param base:
        """

        # table manager
        self.table_manager = TableEntryManager(controller=base,
                                               name="MacController")
        self.table_manager.init_table("egress.mac_c.adjust_mac")

        Event.on("topology_change", self.update)
Ejemplo n.º 10
0
    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.")
Ejemplo n.º 11
0
    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")
Ejemplo n.º 12
0
    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.")
Ejemplo n.º 13
0
    def __init__(self, thrift_port=9090, base=None):
        self.thrift_port = thrift_port
        self.cli = "simple_switch_CLI"

        self.max_port = 8

        self.mcgrp_to_port = defaultdict(list)

        Event.on("igmp_packet_to_controller", self.update_igmp)

        self.table_manager = TableEntryManager(controller=base,
                                               name="GroupController")
        self.table_manager.init_table("ingress.ipv4_c.ipv4_mc")
Ejemplo n.º 14
0
    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)
Ejemplo n.º 15
0
    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)))
Ejemplo n.º 16
0
    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))
Ejemplo n.º 17
0
    def __init__(self, base):
        """
        Init IPv4Controller with base controller and add IPv4 cli commands
        :param base:
        """
        self._baseController = base

        self.table_manager = TableEntryManager(controller=base,
                                               name="IPv4Controller")
        self.table_manager.init_table("ingress.ipv4_c.ipv4")
        self.table_manager.init_table("ingress.ipv4_c.encap_ipv4")

        Event.on("group_update", self.update_based_on_group)

        Event.on("topology_change", self.update_ipv4_rules)
Ejemplo n.º 18
0
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("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()

    # start connection procedure
    init_switches(controller=controller, topology_controller=topology, pd=pd)

    # 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)
Ejemplo n.º 19
0
    def __init__(self, controller=None):
        """
        Initialize PortController with base controller and notification_socket
        :param controller: BaseController which manages SwitchConnection
        :param notification_socket: notification_socket for nanomsg
        """
        # this may be removed later when registers are used
        self.table_manager = TableEntryManager(controller=controller,
                                               name="PortController")

        self.table_manager.init_table(
            table_name="SwitchIngress.port_c.port_status")

        # save port status received by nanomsg message, default up
        self.port_status = defaultdict(lambda: 1)

        Event.on("port_down", self.updatePorts)
Ejemplo n.º 20
0
    def __init__(self, controller=None, notification_socket=None):
        """
        Initialize PortController with base controller and notification_socket
        :param controller: BaseController which manages SwitchConnection
        :param notification_socket: notification_socket for nanomsg
        """
        # this may be removed later when registers are used
        self.table_manager = TableEntryManager(controller=controller, name="PortController")

        self.table_manager.init_table(table_name="ingress.port_c.port_status")

        # save port status received by nanomsg message, default up
        self.port_status = defaultdict(lambda: 1)

        self.sub = nnpy.Socket(nnpy.AF_SP, nnpy.SUB)
        self.sub.connect(notification_socket)
        self.sub.setsockopt(nnpy.SUB, nnpy.SUB_SUBSCRIBE, '')

        Event.on("topology_change", self.update)
Ejemplo n.º 21
0
    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)
Ejemplo n.º 22
0
    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
Ejemplo n.º 23
0
    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)
Ejemplo n.º 24
0
def main():
    Configuration.set('system_done', False)

    # without this line, no events would be fired, no topology discovered and no entries computed
    Event.activate()

    # register event for new switch connections, this will add switches to device list
    Event.on('new_switch_connection', TopologyManager.add_device)

    # base controller
    controller = BaseController()

    # register events for static classes
    Event.on("igmp_packet_in", GroupManager.handle_packet_in)  # handles (un-)sub requests
    Event.on("port_message", TopologyManager.react_to_port_change)
    Event.on("topology_change", TopologyManager.build_domain)

    topology = TopologyController(controller)

    # Create instances of sub controller for CLI
    ipv4 = IPv4Controller(controller)
    bier = BierController(controller)
    #tunnel = TunnelController(controller)

    # add some cli commands for static classes without init
    CLI.add_command("plot_topology", TopologyManager.plot, "Plot topology")
    CLI.add_command("describe_topology", TopologyManager.describe, "Describe topology")
    CLI.add_command("describe_groups", GroupManager.describe, "Describe groups")
    CLI.add_command("show_configuration", Configuration.show_all, "Show all configurations")
    CLI.add_command("table_manager", TableEntryManager.handle_cli_command, "show_tables <controller name>")

    CLI.add_command("load_static_rules", load_static_rules, "Load static rules", ipv4)

    # start global grpc control server
    GRPCServer(listen_port=Configuration.get('listen_port')).start()

    # start connection procedure in thread, so that cli will get initialized and logs can be printed
    threading.Timer(2, connect_to_switches, kwargs={'controller': controller}).start()

    CLI.start_cli()
Ejemplo n.º 25
0
    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)
Ejemplo n.º 26
0
    def __init__(self, p4info_file_path=None, bmv2_path=None):
        self.__p4info_helper = utils.p4runtime_lib.helper.P4InfoHelper(p4info_file_path)
        self.__bmv2_file_path = bmv2_path
        self.__connection = None

        """
        This list is used to purge all current table entries when the
        main controller reconnects to the local controller
        """
        self.entries = []

        Event.on('exit', self.shutdown)
        Event.on('add_entry', self.add_entry)
        Event.on('global_connection', self.purge)  # purge all entries when a new global connection is established
Ejemplo n.º 27
0
    def __init__(self, base):
        """
        Init Tunnelcontroller with base controller and add cli commands
        :param base: basecontroller
        :param type: Sets bier or bier-te type
        """
        self._baseController = base
        Event.on("group_update", self.update_based_on_group)
        Event.on("topology_change", self.update_based_on_topology)

        # add decap rules for devices
        Event.on("switch_connected", self.add_ipv4_decap_rule)

        self.table_manager = TableEntryManager(controller=base,
                                               name="TunnelController")
        self.table_manager.init_table("ingress.tunnel_c.decap_bier")
        self.table_manager.init_table("ingress.tunnel_c.decap_ipv4")
        self.table_manager.init_table("egress.tunnel_c.encap_ipv4")
Ejemplo n.º 28
0
 def __init__(self, controller):
     self.__baseController = controller
     Event.on("topology_packet_in", self.handle_topology_answer)
Ejemplo n.º 29
0
 def __init__(self, listen_port=0):
     self.listen_port = listen_port
     self.running = True
     self.server = grpc.server(futures.ThreadPoolExecutor(max_workers=10))
     Event.on('exit', self.stop)
Ejemplo n.º 30
0
    def TopologyMessage(self, request, context):
        Event.trigger("topology_packet_in", pkt=request)

        return proto.connection_pb2.Status(code=1, message="accepted")