def test_6_same_nlri_same_attributes_order_multivalued(self): # Two routes with same NLRI but and same attributes should # hash to the same values and be equal, *even if* for a said # multivalued attributes, like extended community, the values # appear in a distinct order atts1 = exa.Attributes() ecoms1 = exa.ExtendedCommunities() ecoms1.communities.append(exa.RouteTarget(64512, 1)) ecoms1.communities.append( exa.Encapsulation(exa.Encapsulation.Type.VXLAN)) ecoms1.communities.append(exa.RouteTarget(64512, 2)) atts1.add(ecoms1) atts2 = exa.Attributes() ecoms2 = exa.ExtendedCommunities() ecoms2.communities.append(exa.RouteTarget(64512, 2)) ecoms2.communities.append(exa.RouteTarget(64512, 1)) ecoms2.communities.append( exa.Encapsulation(exa.Encapsulation.Type.VXLAN)) atts2.add(ecoms2) entry1 = engine.RouteEntry(base.NLRI1, None, atts1) entry2 = engine.RouteEntry(base.NLRI1, None, atts2) self.assertEqual(hash(entry1), hash(entry2)) self.assertEqual(entry1, entry2)
def test_4_same_nlri_distinct_attributes(self): # Two routes with same NLRI but distinct attributes should # not be equal atts1 = exa.Attributes() atts1.add(exa.LocalPreference(10)) atts2 = exa.Attributes() atts2.add(exa.LocalPreference(20)) entry1 = engine.RouteEntry(base.NLRI1, None, atts1) entry2 = engine.RouteEntry(base.NLRI1, None, atts2) self.assertNotEqual(entry1, entry2)
def test_5_same_nlri_same_attributes(self): # Two routes with same NLRI but and same attributes should # hash to the same values and be equal. atts1 = exa.Attributes() atts1.add(exa.LocalPreference(10)) atts2 = exa.Attributes() atts2.add(exa.LocalPreference(10)) entry1 = engine.RouteEntry(base.NLRI1, None, atts1) entry2 = engine.RouteEntry(base.NLRI1, None, atts2) self.assertEqual(hash(entry1), hash(entry2)) self.assertEqual(entry1, entry2)
def __init__(self, nlri, rts=None, attributes=None, source=None): if attributes is None: attributes = exa.Attributes() assert isinstance(attributes, exa.Attributes) if rts is not None: assert isinstance(rts, list) assert len(rts) == 0 or isinstance(rts[0], exa.RouteTarget) self.source = source self.afi = nlri.afi self.safi = nlri.safi self.nlri = nlri self.attributes = attributes # a list of exa.bgp.message.update.attribute.community. # extended.RouteTargetASN2Number self._route_targets = [] if exa.Attribute.CODE.EXTENDED_COMMUNITY in self.attributes: ecoms = self.attributes[ exa.Attribute.CODE.EXTENDED_COMMUNITY].communities # use type(..) because isinstance(rtrecord, RouteTarget) is True self._route_targets = [ ecom for ecom in ecoms if type(ecom) == exa.RouteTarget ] if rts: ecoms += rts self._route_targets += rts else: if rts: self.attributes.add(exa.ExtendedCommunities(rts)) self._route_targets += rts
def _new_route_event(self, event_type, nlri, rts, source, nh, lp=0, replaced_route_entry=None, afi=exa.AFI(exa.AFI.ipv4), safi=exa.SAFI(exa.SAFI.mpls_vpn), **kwargs): attributes = exa.Attributes() attributes.add(exa.NextHop(nh)) attributes.add(exa.LocalPreference(lp)) if 'rtrecords' in kwargs: ecoms = exa.ExtendedCommunities() ecoms.communities += kwargs['rtrecords'] attributes.add(ecoms) route_event = engine.RouteEvent(event_type, engine.RouteEntry(nlri, rts, attributes, source), source) route_event.set_replaced_route(replaced_route_entry) LOG.info("*** Emitting event to %s: %s", self.event_target_worker, route_event) self.event_target_worker._on_event(route_event) return route_event
def __init__(self, *args, **kwargs): vpn_instance.VPNInstance.__init__(self, *args, **kwargs) self.gw_port = None # Advertise route to receive multi-destination traffic self.log.info("Generating BGP route for broadcast/multicast traffic") nlri = exa.EVPNMulticast( self.instance_rd, exa.EthernetTag(), exa.IP.create(self.bgp_manager.get_local_address()), None, exa.IP.create(self.bgp_manager.get_local_address())) attributes = exa.Attributes() attributes.add(self._gen_encap_extended_communities()) # add PMSI Tunnel Attribute route attributes.add( exa.PMSIIngressReplication(self.dp_driver.get_local_address(), self.instance_label)) self.multicast_route_entry = engine.RouteEntry(nlri, self.export_rts, attributes) self._advertise_route(self.multicast_route_entry)
def test_8_route_entry_set_rts(self): atts = exa.Attributes() ecoms = exa.ExtendedCommunities() ecoms.communities.append(exa.RouteTarget(64512, 1)) ecoms.communities.append(exa.RouteTarget(64512, 2)) ecoms.communities.append( exa.Encapsulation(exa.Encapsulation.Type.VXLAN)) atts.add(exa.LocalPreference(20)) atts.add(ecoms) entry = engine.RouteEntry(base.NLRI1, None, atts) # check that the route_entry object has the RTs we wanted self.assertIn(exa.RouteTarget(64512, 1), entry.route_targets) self.assertIn(exa.RouteTarget(64512, 2), entry.route_targets) # modify the route targets entry.set_route_targets( [exa.RouteTarget(64512, 3), exa.RouteTarget(64512, 1)]) # check that the new RTs have replaced the old ones self.assertIn(exa.RouteTarget(64512, 1), entry.route_targets) self.assertIn(exa.RouteTarget(64512, 3), entry.route_targets) self.assertNotIn(exa.RouteTarget(64512, 2), entry.route_targets) # also need to check the RTs in the attributes ecoms = entry.attributes[ exa.Attribute.CODE.EXTENDED_COMMUNITY].communities self.assertIn(exa.RouteTarget(64512, 1), ecoms) self.assertIn(exa.RouteTarget(64512, 3), ecoms) self.assertNotIn(exa.RouteTarget(64512, 2), ecoms) # check that other communities were preserved self.assertIn(exa.Encapsulation(exa.Encapsulation.Type.VXLAN), ecoms)
def _new_flow_event(self, event_type, nlri, to_rts, attract_rts, source, afi=exa.AFI(exa.AFI.ipv4), safi=exa.SAFI(exa.SAFI.flow_vpn), **kwargs): attributes = exa.Attributes() ecommunities = exa.ExtendedCommunities() ecommunities.communities.append( exa.TrafficRedirect(exa.ASN(int(to_rts[0].asn)), int(to_rts[0].number)) ) attributes.add(ecommunities) flow_event = engine.RouteEvent(event_type, engine.RouteEntry(nlri, attract_rts, attributes, source), source) self.event_target_worker.enqueue(flow_event) LOG.info("*** Emitting FlowSpec event to %s: %s", self.event_target_worker, flow_event) self._wait() return flow_event
def _route_for_readvertisement(self, route, label, rd, lb_consistent_hash_order, do_default=False): prefix = "0.0.0.0/0" if do_default else route.nlri.cidr.prefix() nlri = self._nlri_from(prefix, label, rd) attributes = exa.Attributes() # new RTRecord = original RTRecord (if any) + orig RTs converted into # RTRecord attributes orig_rtrecords = route.ecoms(exa.RTRecord) rts = route.ecoms(exa.RTExtCom) add_rtrecords = [exa.RTRecord.from_rt(rt) for rt in rts] final_rtrecords = list(set(orig_rtrecords) | set(add_rtrecords)) ecoms = self._gen_encap_extended_communities() ecoms.communities += final_rtrecords ecoms.communities.append( exa.ConsistentHashSortOrder(lb_consistent_hash_order)) attributes.add(ecoms) entry = engine.RouteEntry(nlri, self.readvertise_to_rts, attributes) self.log.debug("RouteEntry for (re-)advertisement: %s", entry) return entry
def test_10_ecoms(self): ecoms1 = exa.ExtendedCommunities() ecoms1.communities.append( exa.Encapsulation(exa.Encapsulation.Type.VXLAN)) atts1 = exa.Attributes() atts1.add(ecoms1) ecoms2 = exa.ExtendedCommunities() ecoms2.communities.append( exa.Encapsulation(exa.Encapsulation.Type.VXLAN)) ecoms2.communities.append(exa.RouteTarget(64512, 1)) atts2 = exa.Attributes() atts2.add(ecoms2) self.assertFalse(atts1.sameValuesAs(atts2)) self.assertFalse(atts2.sameValuesAs(atts1))
def __init__(self, re, keep_attributes=None): if keep_attributes is None: keep_attributes = keep_attributes_default attributes = exa.Attributes() for (attribute_id, attribute) in re.attributes.items(): if attribute_id in keep_attributes: attributes.add(attribute) super(FilteredRoute, self).__init__(re.nlri, None, attributes)
def __init__(self, re, keep_attributes=None): if keep_attributes is None: keep_attributes = keep_attributes_default attributes = exa.Attributes() for (attribute_id, attribute) in re.attributes.items(): if attribute_id in keep_attributes: attributes.add(attribute) engine.RouteEntry.__init__(self, re.nlri, None, attributes)
def _default_route_for_advertisement(self, endpoint): label, rd, lb_consistent_hash_order = ( self._get_route_params_for_endpoint(endpoint)) self.log.debug( "Default route (re-)advertisement with label %s and " "route distinguisher %s", label, rd) nlri = self._nlri_from(DEFAULT_ADDR_PREFIX, label, rd) attributes = exa.Attributes() ecoms = self._gen_encap_extended_communities() ecoms.communities.append( exa.ConsistentHashSortOrder(lb_consistent_hash_order)) attributes.add(ecoms) entry = engine.RouteEntry(nlri, self.readvertise_to_rts, attributes) self.log.debug("RouteEntry for default prefix advertisement: %s", entry) return entry
def _redirect_route_for_readvertisement(self, route): # Create a FlowSpec NLRI with distinct RD and a copy of rules from # FlowSpec route to readvertise nlri = flowspec.FlowRouteFactory(self.afi, self.instance_rd) nlri.rules = route.nlri.rules attributes = exa.Attributes() ecoms = exa.ExtendedCommunities() ecoms.communities += (self._gen_rtrecords_extended_community( route.ecoms)) assert len(self.attract_rts) == 1 rt = self.attract_rts[0] ecoms.communities.append( exa.TrafficRedirect(exa.ASN(int(rt.asn)), int(rt.number))) attributes.add(ecoms) entry = engine.RouteEntry(nlri, self.readvertise_to_rts, attributes) self.log.debug("RouteEntry for redirect (re-)advertisement: %s", entry) return entry
def _route_for_readvertisement(self, route, endpoint): label, rd, lb_consistent_hash_order = ( self._get_route_params_for_endpoint(endpoint)) self.log.debug( "Prefix %s (re-)advertisement with label %s and route " "distinguisher %s", route.nlri.cidr.prefix(), label, rd) nlri = self._nlri_from(route.nlri.cidr.prefix(), label, rd) attributes = exa.Attributes() ecoms = self._gen_encap_extended_communities() ecoms.communities += (self._gen_rtrecords_extended_community( route.ecoms)) ecoms.communities.append( exa.ConsistentHashSortOrder(lb_consistent_hash_order)) attributes.add(ecoms) entry = engine.RouteEntry(nlri, self.readvertise_to_rts, attributes) self.log.debug("RouteEntry for (re-)advertisement: %s", entry) return entry
def test_9_route_entry_rts_as_init_param(self): atts = exa.Attributes() ecoms = exa.ExtendedCommunities() ecoms.communities.append( exa.Encapsulation(exa.Encapsulation.Type.VXLAN)) atts.add(exa.LocalPreference(20)) atts.add(ecoms) rts = [exa.RouteTarget(64512, 1), exa.RouteTarget(64512, 2)] entry = engine.RouteEntry(base.NLRI1, rts, atts) self.assertIn(exa.RouteTarget(64512, 1), entry.route_targets) self.assertIn(exa.RouteTarget(64512, 2), entry.route_targets) ecoms = entry.attributes[ exa.Attribute.CODE.EXTENDED_COMMUNITY].communities self.assertIn(exa.RouteTarget(64512, 1), ecoms) self.assertIn(exa.RouteTarget(64512, 2), ecoms) self.assertIn(exa.Encapsulation(exa.Encapsulation.Type.VXLAN), ecoms)
def _new_flow_event(self, event_type, nlri, to_rts, attract_rts, source, afi=exa.AFI(exa.AFI.ipv4), safi=exa.SAFI(exa.SAFI.flow_vpn), **kwargs): attributes = exa.Attributes() ecommunities = exa.ExtendedCommunities() ecommunities.communities.append( exa.TrafficRedirect(exa.ASN(int(to_rts[0].asn)), int(to_rts[0].number)) ) attributes.add(ecommunities) flow_event = engine.RouteEvent(event_type, engine.RouteEntry(nlri, attract_rts, attributes, source), source) self.event_target_worker._on_event(flow_event) return flow_event
def __init__(self, *args, **kwargs): vpn_instance.VPNInstance.__init__(self, *args, **kwargs) self.gw_port = None encaps = self.dp_driver.supported_encaps() if (exa.Encapsulation(exa.Encapsulation.Type.VXLAN) in encaps and any([ exa.Encapsulation(exa.Encapsulation.Type.MPLS) in encaps, exa.Encapsulation(exa.Encapsulation.Type.GRE) in encaps, exa.Encapsulation(exa.Encapsulation.Type.MPLS_UDP) in encaps ])): raise Exception("The dataplane can't support both an MPLS encap " "and a VXLAN encapsulation") # Advertise route to receive multi-destination traffic self.log.info("Generating BGP route for broadcast/multicast traffic") nlri = exa.EVPNMulticast( self.instance_rd, exa.EthernetTag(), exa.IP.create(self.bgp_manager.get_local_address()), None, exa.IP.create(self.bgp_manager.get_local_address())) attributes = exa.Attributes() attributes.add(self._gen_encap_extended_communities()) # add PMSI Tunnel Attribute route attributes.add( exa.PMSIIngressReplication(self.dp_driver.get_local_address(), raw_label=self.instance_label)) self.multicast_route_entry = engine.RouteEntry(nlri, self.export_rts, attributes) self._advertise_route(self.multicast_route_entry)
def test_f1_test_empty_rt(self): # worker advertises a route with no RT w1 = self._new_worker("Worker1", worker.Worker) subscribe = engine.Subscription(exa.AFI(exa.AFI.ipv4), exa.SAFI(exa.SAFI.mpls_vpn), None, w1) self.rtm.enqueue(subscribe) w2 = self._new_worker("Worker2", worker.Worker) route_event = engine.RouteEvent( engine.RouteEvent.ADVERTISE, engine.RouteEntry(t.NLRI1, None, exa.Attributes()), w2) self.rtm.enqueue(route_event) self._wait() self.assertEqual( 1, w1.enqueue.call_count, "1 route advertised should be synthesized to Worker1")