def update_bier_encap_entry(self, switch=None): """ Add bier encap entry for given prefix :param switch: switch where rules should be installed :return: """ valid_entries = [] for mc_addr in GroupManager.get_mc_addresses(): for domain in GroupManager.get_domains_for_mc_addr(mc_addr): domain = int(domain) bitstring = BierComputation.compute_bier_header( mc_addr=mc_addr, domain=domain) entry = TableEntry(switch=switch, match_fields={ "hdr.ipv4.dstAddr": mc_addr, }, action_name="ingress.ipv4_c.add_bier", action_params={"bs": bitstring}) if TableEntryManager.handle_table_entry( manager=self.table_manager, table_name="ingress.ipv4_c.encap_ipv4", table_entry=entry): Log.async_debug("Installed encap ipv4 rule for", switch, mc_addr, bitstring) valid_entries.append(entry.match_fields) self.table_manager.remove_invalid_entries( switch=switch, table_name="ingress.ipv4_c.encap_ipv4", valid_entries=valid_entries)
def update_ipv4_entries(self, switch=None): """ Update ipv4 entries based on shortest path on switch :param switch: switch where ipv4 entries will be installed :return: """ paths = TopologyManager.get_paths(domain_id=0) valid_entries = [] cur_dev = TopologyManager.get_device(switch) for dst in [d for d in paths.get(switch, {}) if d != switch]: # don't check path from i->i # get the next_hop towards the destination along the shortest path dst_dev = TopologyManager.get_device(dst) next_hop = TopologyManager.get_next_hop(start_node=switch, destination_node=dst, domain_id=0) port = cur_dev.get_device_to_port(next_hop.get_name()) entry = TableEntry( switch=switch, match_fields={ "hdr.ipv4.dstAddr": (str(dst_dev.get_ip()), 32), "meta.ports.status": (BierComputation.id_to_bitstring(id=int(port)), BierComputation.id_to_bitstring(id=int(port))) }, action_name="ingress.ipv4_c.forward", action_params={"port": int(port)}, priority=1) if TableEntryManager.handle_table_entry( manager=self.table_manager, table_name="ingress.ipv4_c.ipv4", table_entry=entry): Log.async_debug("Installed IPv4 forwarding rule for", switch, "->", dst) valid_entries.append(entry.match_fields) # Add decap entry entry = TableEntry( switch=cur_dev.get_name(), match_fields={"hdr.ipv4.dstAddr": (str(cur_dev.get_ip()), 32)}, action_name="ingress.ipv4_c.decap", priority=1) if TableEntryManager.handle_table_entry( manager=self.table_manager, table_name="ingress.ipv4_c.ipv4", table_entry=entry): Log.async_debug("Installed IPv4 decap rule for", switch) valid_entries.append(entry.match_fields) return valid_entries
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 add_ipv4_decap_rule(self, *args, **kwargs): """ Adds an ipv4 decap rule for the switch This event is triggered when a switch is arbitrated :return: """ device = TopologyManager.get_device(kwargs.get('name')) entry = TableEntry(switch=device.get_name(), match_fields={"hdr.ipv4.dstAddr": device.get_ip()}, action_name="ingress.tunnel_c.ipv4_decap") if TableEntryManager.handle_table_entry( manager=self.table_manager, table_name="ingress.tunnel_c.decap_ipv4", table_entry=entry): Log.async_debug("Ipv4 decap rule installed for", kwargs.get('name'))
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 update_bier_decap_rule(self, switch=None): """ Updates the bier decap rules based on the current topology :param switch: switch where decap rules should be installed :return: """ valid_entries = [] # bier decap rules for domain in TopologyManager.get_domain_for_device(switch): domain = int(domain) bfr_id = BierComputation.id_to_bitstring( TopologyManager.get_device(switch).get_bfr_id(domain)) entry = TableEntry(switch=switch, match_fields={ "hdr.bier[0].BitString": (bfr_id, bfr_id), "hdr.bier[0].Domain": domain }, action_name="ingress.tunnel_c.bier_decap", action_params={"decapBit": bfr_id}, priority=1) if TableEntryManager.handle_table_entry( manager=self.table_manager, table_name="ingress.tunnel_c.decap_bier", table_entry=entry): Log.async_debug("BIER decap rule updated on", switch, "for domain", domain) valid_entries.append(entry.match_fields) self.table_manager.remove_invalid_entries( switch=switch, table_name="ingress.tunnel_c.decap_bier", valid_entries=valid_entries)
def update_bier_forwarding_entries(self, switch=None): """ Adds bier forwarding entry for given switch in specifc domain :param switch: :param domain: domain identifier :return: """ table_name = "ingress.bier_c.bift" valid_entries = [] for domain in TopologyManager.get_domain_for_device(switch): domain = int(domain) bift = BierComputation.build_bift(switch=switch, domain=domain) for entry in bift: bit_string = BierComputation.id_to_bitstring(id=entry) out_port = TopologyManager.get_device( switch).get_device_to_port(bift.get(entry)[1]) # generate default bier entry e = TableEntry( switch=switch, match_fields={ "meta.bier_md.remainingBits": (bit_string, bit_string), "meta.ports.status": (BierComputation.id_to_bitstring(id=out_port), BierComputation.id_to_bitstring(id=out_port)) }, action_name="ingress.bier_c.forward", action_params={ "fbm": bift.get(entry)[0], "port": out_port }, priority=1) if TableEntryManager.handle_table_entry( manager=self.table_manager, table_name=table_name, table_entry=e): Log.async_debug("Installed BIER rule for", switch, "to bfr-id", entry) valid_entries.append(e.match_fields) # generate bier-frr link protection entry for this switch and bfr if Configuration.get('protection') == 'Link': frr_entry = self.update_frr_link_protection( switch=switch, domain=domain, port=out_port, to_id=entry, fbm=bift.get(entry)[0], next_hop=bift.get(entry)[1]) if TableEntryManager.handle_table_entry( manager=self.table_manager, table_name=table_name, table_entry=frr_entry): Log.async_debug( "Installed BIER-FRR link protection rule for", switch) valid_entries.append(frr_entry.match_fields) # generate bier-frr node protection entry for this switch and bfr if Configuration.get('protection') == 'Node': frr_entry = self.update_frr_node_protection( switch=switch, domain=domain, port=out_port, to_id=entry, fbm=bift.get(entry)[0], next_hop=bift.get(entry)[1]) if frr_entry: if TableEntryManager.handle_table_entry( manager=self.table_manager, table_name=table_name, table_entry=frr_entry): Log.async_debug( "Installed BIER-FRR node protection rule for", switch, "to", entry) valid_entries.append(frr_entry.match_fields) bfr_id = BierComputation.id_to_bitstring( TopologyManager.get_device(switch).get_bfr_id(0)) # Add decap entry entry = TableEntry( switch=switch, match_fields={"meta.bier_md.remainingBits": (bfr_id, bfr_id)}, action_name="ingress.bier_c.decap", action_params={"decapBit": bfr_id}, priority=1) if TableEntryManager.handle_table_entry(manager=self.table_manager, table_name=table_name, table_entry=entry): Log.async_debug("Installed BIER decap rule for", switch) valid_entries.append(entry.match_fields) self.table_manager.remove_invalid_entries(switch=switch, table_name=table_name, valid_entries=valid_entries)