def run(gobgpd_addr, vrf_name, prefix, nexthop): channel = implementations.insecure_channel(gobgpd_addr, 50051) with gobgp_pb2.beta_create_GobgpApi_stub(channel) as stub: subnet = IPNetwork(prefix) ipaddr = subnet.ip masklen = subnet.prefixlen nlri = IPAddrPrefix(addr=ipaddr, length=masklen) bin_nlri = nlri.serialize() nexthop = BGPPathAttributeNextHop(value=nexthop) bin_nexthop = nexthop.serialize() origin = BGPPathAttributeOrigin(value=2) bin_origin = origin.serialize() pattrs = [] pattrs.append(str(bin_nexthop)) pattrs.append(str(bin_origin)) path = {} path['nlri'] = str(bin_nlri) path['pattrs'] = pattrs uuid = stub.ModPath(gobgp_pb2.ModPathArguments(resource=Resource_VRF, name=vrf_name, path=path), _TIMEOUT_SECONDS) if uuid: print "Success!" else: print "Error!"
def add_to_global_table(self, prefix, nexthop=None, is_withdraw=False): src_ver_num = 1 peer = None # set mandatory path attributes origin = BGPPathAttributeOrigin(BGP_ATTR_ORIGIN_IGP) aspath = BGPPathAttributeAsPath([[]]) pathattrs = OrderedDict() pathattrs[BGP_ATTR_TYPE_ORIGIN] = origin pathattrs[BGP_ATTR_TYPE_AS_PATH] = aspath net = netaddr.IPNetwork(prefix) ip = str(net.ip) masklen = net.prefixlen if netaddr.valid_ipv4(ip): _nlri = IPAddrPrefix(masklen, ip) if nexthop is None: nexthop = '0.0.0.0' p = Ipv4Path else: _nlri = IP6AddrPrefix(masklen, ip) if nexthop is None: nexthop = '::' p = Ipv6Path new_path = p(peer, _nlri, src_ver_num, pattrs=pathattrs, nexthop=nexthop, is_withdraw=is_withdraw) # add to global ipv4 table and propagates to neighbors self.learn_path(new_path)
def run(gobgpd_addr, routefamily): channel = implementations.insecure_channel(gobgpd_addr, 50051) with gobgp_pb2.beta_create_GobgpApi_stub(channel) as stub: ribs = stub.MonitorBestChanged(gobgp_pb2.Arguments(family=routefamily), _TIMEOUT_SECONDS) for rib in ribs: paths_target = rib.paths for path_target in paths_target: nlri = IPAddrPrefix.parser(path_target.nlri) print "----------------------------" print (" Rib.prefix : %s" % nlri[0].prefix) for pattr in path_target.pattrs: path_attr = _PathAttribute.parser(pattr) if isinstance(path_attr[0], BGPPathAttributeOrigin): print (" Rib.origin : %s" % path_attr[0].value) elif isinstance(path_attr[0], BGPPathAttributeAsPath): if path_attr[0].type == 2: print(" Rib.aspath : %s" % path_attr[0].value) else: print(" Rib.aspath : ???") elif isinstance(path_attr[0], BGPPathAttributeMultiExitDisc): print (" Rib.med : %s" % path_attr[0].value) elif isinstance(path_attr[0], BGPPathAttributeNextHop): print (" Rib.nexthop : %s" % path_attr[0].value) elif isinstance(path_attr[0], BGPPathAttributeCommunities): for community in path_attr[0].communities: print(" Rib.community : %s" % community) print (" Rib.is_withdraw : %s" % path_target.is_withdraw)
def modpath(self,gobgpd_addr,originate_path_list): channel = implementations.insecure_channel(gobgpd_addr, 50051) with gobgp_pb2.beta_create_GobgpApi_stub(channel) as stub: paths = [] for originate_path in originate_path_list: pattrs = [] path = {} subnet = IPNetwork(originate_path['route']) ver = subnet.version addr = subnet.ip mask = subnet.prefixlen if ver == 4: nlri = IPAddrPrefix(addr=addr, length=mask) nexthop = BGPPathAttributeNextHop(value=originate_path['next_hop']) else : nlri = IP6AddrPrefix(addr=addr, length=mask) nexthop = BGPPathAttributeMpReachNLRI(next_hop = originate_path['next_hop'],nlri = [nlri],afi = AFI_IPV6 , safi = SAFI_UNICAST) bin_nlri = nlri.serialize() bin_nexthop = nexthop.serialize() pattrs.append(str(bin_nexthop)) origin = BGPPathAttributeOrigin(value=ORIGIN) bin_origin = origin.serialize() pattrs.append(str(bin_origin)) if originate_path['community'] : community_set = self.community_convert(originate_path['community']) communities = BGPPathAttributeCommunities(communities=community_set) bin_communities = communities.serialize() pattrs.append(str(bin_communities)) #as_path = BGPPathAttributeAs4Path(value=[[1234,1111]]) #bin_as_path = as_path.serialize() #pattrs.append(str(bin_as_path)) path['nlri'] = str(bin_nlri) path['pattrs'] = pattrs paths.append(path) args = [] args.append(gobgp_pb2.ModPathsArguments(resource=Resource_GLOBAL, paths=paths)) ret = stub.ModPaths(args, _TIMEOUT_SECONDS)
def add_to_vrf(self, route_dist, prefix, next_hop, route_family): """Adds `prefix` to VRF identified by `route_dist` with given `next_hop`. Returns assigned VPN label. """ from ryu.services.protocols.bgp.core import BgpCoreError assert route_dist and prefix and next_hop if route_family not in (VRF_RF_IPV4, VRF_RF_IPV6): raise ValueError('Given route_family %s is not supported.' % route_family) vrf_table = None table_id = (route_dist, route_family) if route_family == VRF_RF_IPV4: vrf_table = self._tables.get(table_id) if vrf_table is None: raise BgpCoreError(desc='VRF table for RD: %s does not ' 'exist.' % route_dist) if not is_valid_ipv4_prefix(prefix) or not is_valid_ipv4(next_hop): raise BgpCoreError(desc='Invalid Ipv4 prefix or nexthop.') ip, masklen = prefix.split('/') prefix = IPAddrPrefix(int(masklen), ip) elif route_family == VRF_RF_IPV6: vrf_table = self._tables.get(table_id) if vrf_table is None: raise BgpCoreError(desc='VRF table for RD: %s does not ' 'exist.' % route_dist) if not is_valid_ipv6_prefix(prefix) or not is_valid_ipv6(next_hop): raise BgpCoreError(desc='Invalid Ipv6 prefix or nexthop.') ip6, masklen = prefix.split('/') prefix = IP6AddrPrefix(int(masklen), ip6) return vrf_table.insert_vrf_path( prefix, next_hop=next_hop, gen_lbl=True )
def test_update_vrf_table_invalid_route_family(self): # Prepare test data route_dist = '65000:100' ip_network = '192.168.0.0' ip_prefix_len = 24 prefix_str = '%s/%d' % (ip_network, ip_prefix_len) prefix_inst = IPAddrPrefix(ip_prefix_len, ip_network) next_hop = '10.0.0.1' route_family = 'foobar' # invalid route_type = None # should be ignored kwargs = {} # should be ignored self._test_update_vrf_table(prefix_inst, route_dist, prefix_str, next_hop, route_family, route_type, **kwargs)
def remove_from_vrf(self, route_dist, prefix, route_family): """Removes `prefix` from VRF identified by `route_dist`. Returns assigned VPN label. """ from ryu.services.protocols.bgp.core import BgpCoreError # Validate given if route_family not in (VRF_RF_IPV4, VRF_RF_IPV6): raise BgpCoreError(desc='Unsupported route family %s' % route_family) val_ipv4 = route_family == VRF_RF_IPV4\ and is_valid_ipv4_prefix(prefix) val_ipv6 = route_family == VRF_RF_IPV6\ and is_valid_ipv6_prefix(prefix) if not val_ipv4 and not val_ipv6: raise BgpCoreError(desc='Invalid prefix or nexthop.') table_id = (route_dist, route_family) if route_family == VRF_RF_IPV4: vrf_table = self._tables.get(table_id) if not vrf_table: raise BgpCoreError(desc='Vrf for route distinguisher %s does ' 'not exist.' % route_dist) ip, masklen = prefix.split('/') prefix = IPAddrPrefix(int(masklen), ip) else: vrf_table = self._tables.get(table_id) if not vrf_table: raise BgpCoreError(desc='Vrf for route distinguisher %s does ' 'not exist.' % route_dist) ip6, masklen = prefix.split('/') prefix = IP6AddrPrefix(int(masklen), ip6) # We do not check if we have a path to given prefix, we issue # withdrawal. Hence multiple withdrawals have not side effect. return vrf_table.insert_vrf_path(prefix, is_withdraw=True)
def remove_from_vrf(self, route_dist, prefix, route_family): """Removes `prefix` from VRF identified by `route_dist`. Returns assigned VPN label. """ from ryu.services.protocols.bgp.core import BgpCoreError # Validate given if route_family not in (VRF_RF_IPV4, VRF_RF_IPV6): raise BgpCoreError(desc='Unsupported route family %s' % route_family) val_ipv4 = route_family == VRF_RF_IPV4\ and is_valid_ipv4_prefix(prefix) val_ipv6 = route_family == VRF_RF_IPV6\ and is_valid_ipv6_prefix(prefix) if not val_ipv4 and not val_ipv6: raise BgpCoreError(desc='Invalid prefix or nexthop.') table_id = (route_dist, route_family) if route_family == VRF_RF_IPV4: vrf_table = self._tables.get(table_id) if not vrf_table: raise BgpCoreError(desc='Vrf for route distinguisher %s does ' 'not exist.' % route_dist) ip, masklen = prefix.split('/') prefix = IPAddrPrefix(int(masklen), ip) else: vrf_table = self._tables.get(table_id) if not vrf_table: raise BgpCoreError(desc='Vrf for route distinguisher %s does ' 'not exist.' % route_dist) ip6, masklen = prefix.split('/') prefix = IP6AddrPrefix(int(masklen), ip) # We do not check if we have a path to given prefix, we issue # withdrawal. Hence multiple withdrawals have not side effect. return vrf_table.insert_vrf_path(prefix, is_withdraw=True)
def test_update_vrf_table_ipv4_withdraw(self): # Prepare test data route_dist = '65000:100' ip_network = '192.168.0.0' ip_prefix_len = 24 prefix_str = '%s/%d' % (ip_network, ip_prefix_len) prefix_inst = IPAddrPrefix(ip_prefix_len, ip_network) next_hop = '10.0.0.1' route_family = VRF_RF_IPV4 route_type = None # should be ignored kwargs = {} # should be ignored self._test_update_vrf_table(prefix_inst, route_dist, prefix_str, next_hop, route_family, route_type, is_withdraw=True, **kwargs)
def monitor_bestpath_chenged(self, arguments): ribs = self.g_conn.MonitorBestChanged(api.Arguments(**arguments), self.monitor_timeout) for rib in ribs: for path in rib.paths: nlri = IPAddrPrefix.parser(path.nlri) prefix = nlri[0].prefix log.debug( 'Recv bgp route from gobgp: prefix={0}, withdraw={1}'. format(prefix, path.is_withdraw)) bgp_path = { 'prefix': prefix, 'metric': 0, 'is_withdraw': path.is_withdraw } bgp_pathattr = { 'BGP_uptime': '', 'BGP_iBGP': '', 'BGP_flags': '', 'BGP_internal': '', 'BGP_loc_pref': '0' } for pattr in path.pattrs: path_attr = _PathAttribute.parser(pattr) if isinstance(path_attr[0], BGPPathAttributeOrigin): origin = path_attr[0].value if origin == 0: bgp_pathattr['BGP_origin'] = 'i' elif origin == 1: bgp_pathattr['BGP_origin'] = 'e' else: bgp_pathattr['BGP_origin'] = '?' elif isinstance(path_attr[0], BGPPathAttributeAsPath): if path_attr[0].type == 2: bgp_pathattr['BGP_AS_path'] = '{0}'.format( path_attr[0].value[0][0]) elif isinstance(path_attr[0], BGPPathAttributeMultiExitDisc): bgp_path['BGP_MED'] = path_attr[0].value elif isinstance(path_attr[0], BGPPathAttributeNextHop): bgp_path['nexthop'] = path_attr[0].value elif isinstance(path_attr[0], BGPPathAttributeCommunities): communities = [] for community in path_attr[0].communities: communities.append(community) bgp_pathattr['BGP_Community'] = ','.join(communities) bgp_path['bgp_pathattr'] = bgp_pathattr self.o_hdr.mod_bgp_path(bgp_path)
def add_to_ipv4_global_table(self, prefix, is_withdraw=False): ip, masklen = prefix.split('/') _nlri = IPAddrPrefix(int(masklen), ip) src_ver_num = 1 peer = None # set mandatory path attributes nexthop = '0.0.0.0' origin = BGPPathAttributeOrigin(BGP_ATTR_ORIGIN_IGP) aspath = BGPPathAttributeAsPath([[]]) pathattrs = OrderedDict() pathattrs[BGP_ATTR_TYPE_ORIGIN] = origin pathattrs[BGP_ATTR_TYPE_AS_PATH] = aspath new_path = Ipv4Path(peer, _nlri, src_ver_num, pattrs=pathattrs, nexthop=nexthop, is_withdraw=is_withdraw) # add to global ipv4 table and propagates to neighbors self.learn_path(new_path)
def update_global_table(self, prefix, next_hop=None, is_withdraw=False): """Update a BGP route in the Global table for the given `prefix` with the given `next_hop`. If `is_withdraw` is False, which is the default, add a BGP route to the Global table. If `is_withdraw` is True, remove a BGP route from the Global table. """ src_ver_num = 1 peer = None # set mandatory path attributes origin = BGPPathAttributeOrigin(BGP_ATTR_ORIGIN_IGP) aspath = BGPPathAttributeAsPath([[]]) pathattrs = OrderedDict() pathattrs[BGP_ATTR_TYPE_ORIGIN] = origin pathattrs[BGP_ATTR_TYPE_AS_PATH] = aspath net = netaddr.IPNetwork(prefix) addr = str(net.ip) masklen = net.prefixlen if ip.valid_ipv4(addr): _nlri = IPAddrPrefix(masklen, addr) if next_hop is None: next_hop = '0.0.0.0' p = Ipv4Path else: _nlri = IP6AddrPrefix(masklen, addr) if next_hop is None: next_hop = '::' p = Ipv6Path new_path = p(peer, _nlri, src_ver_num, pattrs=pathattrs, nexthop=next_hop, is_withdraw=is_withdraw) # add to global table and propagates to neighbors self.learn_path(new_path)
def update_vrf_table(self, route_dist, prefix=None, next_hop=None, route_family=None, route_type=None, tunnel_type=None, is_withdraw=False, redundancy_mode=None, pmsi_tunnel_type=None, **kwargs): """Update a BGP route in the VRF table identified by `route_dist` with the given `next_hop`. If `is_withdraw` is False, which is the default, add a BGP route to the VRF table identified by `route_dist` with the given `next_hop`. If `is_withdraw` is True, remove a BGP route from the VRF table and the given `next_hop` is ignored. If `route_family` is VRF_RF_L2_EVPN, `route_type` and `kwargs` are required to construct EVPN NLRI and `prefix` is ignored. ``redundancy_mode`` specifies a redundancy mode type. ` `pmsi_tunnel_type` specifies the type of the PMSI tunnel attribute used to encode the multicast tunnel identifier. This field is advertised only if route_type is EVPN_MULTICAST_ETAG_ROUTE. Returns assigned VPN label. """ from ryu.services.protocols.bgp.core import BgpCoreError assert route_dist if is_withdraw: gen_lbl = False next_hop = None else: gen_lbl = True if not (is_valid_ipv4(next_hop) or is_valid_ipv6(next_hop)): raise BgpCoreError(desc='Invalid IPv4/IPv6 nexthop: %s' % next_hop) vrf_table = self._tables.get((route_dist, route_family)) if vrf_table is None: raise BgpCoreError( desc='VRF table does not exist: route_dist=%s, ' 'route_family=%s' % (route_dist, route_family)) vni = kwargs.get('vni', None) if route_family == VRF_RF_IPV4: if not is_valid_ipv4_prefix(prefix): raise BgpCoreError(desc='Invalid IPv4 prefix: %s' % prefix) ip, masklen = prefix.split('/') prefix = IPAddrPrefix(int(masklen), ip) elif route_family == VRF_RF_IPV6: if not is_valid_ipv6_prefix(prefix): raise BgpCoreError(desc='Invalid IPv6 prefix: %s' % prefix) ip6, masklen = prefix.split('/') prefix = IP6AddrPrefix(int(masklen), ip6) elif route_family == VRF_RF_L2_EVPN: assert route_type if route_type == EvpnMacIPAdvertisementNLRI.ROUTE_TYPE_NAME: # MPLS labels will be assigned automatically kwargs['mpls_labels'] = [] if route_type == EvpnInclusiveMulticastEthernetTagNLRI.ROUTE_TYPE_NAME: # Inclusive Multicast Ethernet Tag Route does not have "vni", # omit "vni" from "kwargs" here. vni = kwargs.pop('vni', None) subclass = EvpnNLRI._lookup_type_name(route_type) kwargs['route_dist'] = route_dist esi = kwargs.get('esi', None) if esi is not None: if isinstance(esi, dict): esi_type = esi.get('type', 0) esi_class = EvpnEsi._lookup_type(esi_type) kwargs['esi'] = esi_class.from_jsondict(esi) else: # isinstance(esi, numbers.Integral) kwargs['esi'] = EvpnArbitraryEsi( type_desc.Int9.from_user(esi)) if vni is not None: # Disable to generate MPLS labels, # because encapsulation type is not MPLS. from ryu.services.protocols.bgp.api.prefix import ( TUNNEL_TYPE_VXLAN, TUNNEL_TYPE_NVGRE) assert tunnel_type in [ None, TUNNEL_TYPE_VXLAN, TUNNEL_TYPE_NVGRE ] gen_lbl = False prefix = subclass(**kwargs) else: raise BgpCoreError(desc='Unsupported route family %s' % route_family) # We do not check if we have a path to given prefix, we issue # withdrawal. Hence multiple withdrawals have not side effect. return vrf_table.insert_vrf_path(nlri=prefix, next_hop=next_hop, gen_lbl=gen_lbl, is_withdraw=is_withdraw, redundancy_mode=redundancy_mode, vni=vni, tunnel_type=tunnel_type, pmsi_tunnel_type=pmsi_tunnel_type)
def update_vrf_table(self, route_dist, prefix=None, next_hop=None, route_family=None, route_type=None, tunnel_type=None, is_withdraw=False, **kwargs): """Update a BGP route in the VRF table identified by `route_dist` with the given `next_hop`. If `is_withdraw` is False, which is the default, add a BGP route to the VRF table identified by `route_dist` with the given `next_hop`. If `is_withdraw` is True, remove a BGP route from the VRF table and the given `next_hop` is ignored. If `route_family` is VRF_RF_L2_EVPN, `route_type` and `kwargs` are required to construct EVPN NLRI and `prefix` is ignored. Returns assigned VPN label. """ from ryu.services.protocols.bgp.core import BgpCoreError assert route_dist if is_withdraw: gen_lbl = False next_hop = None else: gen_lbl = True if not (is_valid_ipv4(next_hop) or is_valid_ipv6(next_hop)): raise BgpCoreError(desc='Invalid IPv4/IPv6 nexthop: %s' % next_hop) vrf_table = self._tables.get((route_dist, route_family)) if vrf_table is None: raise BgpCoreError( desc='VRF table does not exist: route_dist=%s, ' 'route_family=%s' % (route_dist, route_family)) if route_family == VRF_RF_IPV4: if not is_valid_ipv4_prefix(prefix): raise BgpCoreError(desc='Invalid IPv4 prefix: %s' % prefix) ip, masklen = prefix.split('/') prefix = IPAddrPrefix(int(masklen), ip) elif route_family == VRF_RF_IPV6: if not is_valid_ipv6_prefix(prefix): raise BgpCoreError(desc='Invalid IPv6 prefix: %s' % prefix) ip6, masklen = prefix.split('/') prefix = IP6AddrPrefix(int(masklen), ip6) elif route_family == VRF_RF_L2_EVPN: assert route_type if route_type == EvpnMacIPAdvertisementNLRI.ROUTE_TYPE_NAME: # MPLS labels will be assigned automatically kwargs['mpls_labels'] = [] subclass = EvpnNLRI._lookup_type_name(route_type) kwargs['route_dist'] = route_dist esi = kwargs.get('esi', None) if esi is not None: # Note: Currently, we support arbitrary 9-octet ESI value only. kwargs['esi'] = EvpnArbitraryEsi(type_desc.Int9.from_user(esi)) if 'vni' in kwargs: # Disable to generate MPLS labels, because encapsulation type # is not MPLS. from ryu.services.protocols.bgp.api.prefix import ( TUNNEL_TYPE_VXLAN, TUNNEL_TYPE_NVGRE) assert tunnel_type in [TUNNEL_TYPE_VXLAN, TUNNEL_TYPE_NVGRE] gen_lbl = False prefix = subclass(**kwargs) else: raise BgpCoreError(desc='Unsupported route family %s' % route_family) # We do not check if we have a path to given prefix, we issue # withdrawal. Hence multiple withdrawals have not side effect. return vrf_table.insert_vrf_path(nlri=prefix, next_hop=next_hop, gen_lbl=gen_lbl, is_withdraw=is_withdraw, tunnel_type=tunnel_type)
def update_vrf_table(self, route_dist, prefix=None, next_hop=None, route_family=None, route_type=None, tunnel_type=None, is_withdraw=False, **kwargs): """Update a BGP route in the VRF table identified by `route_dist` with the given `next_hop`. If `is_withdraw` is False, which is the default, add a BGP route to the VRF table identified by `route_dist` with the given `next_hop`. If `is_withdraw` is True, remove a BGP route from the VRF table and the given `next_hop` is ignored. If `route_family` is VRF_RF_L2_EVPN, `route_type` and `kwargs` are required to construct EVPN NLRI and `prefix` is ignored. Returns assigned VPN label. """ from ryu.services.protocols.bgp.core import BgpCoreError assert route_dist if is_withdraw: gen_lbl = False next_hop = None else: gen_lbl = True if not (is_valid_ipv4(next_hop) or is_valid_ipv6(next_hop)): raise BgpCoreError( desc='Invalid IPv4/IPv6 nexthop: %s' % next_hop) vrf_table = self._tables.get((route_dist, route_family)) if vrf_table is None: raise BgpCoreError( desc='VRF table does not exist: route_dist=%s, ' 'route_family=%s' % (route_dist, route_family)) if route_family == VRF_RF_IPV4: if not is_valid_ipv4_prefix(prefix): raise BgpCoreError(desc='Invalid IPv4 prefix: %s' % prefix) ip, masklen = prefix.split('/') prefix = IPAddrPrefix(int(masklen), ip) elif route_family == VRF_RF_IPV6: if not is_valid_ipv6_prefix(prefix): raise BgpCoreError(desc='Invalid IPv6 prefix: %s' % prefix) ip6, masklen = prefix.split('/') prefix = IP6AddrPrefix(int(masklen), ip6) elif route_family == VRF_RF_L2_EVPN: assert route_type if route_type == EvpnMacIPAdvertisementNLRI.ROUTE_TYPE_NAME: # MPLS labels will be assigned automatically kwargs['mpls_labels'] = [] subclass = EvpnNLRI._lookup_type_name(route_type) kwargs['route_dist'] = route_dist esi = kwargs.get('esi', None) if esi is not None: # Note: Currently, we support arbitrary 9-octet ESI value only. kwargs['esi'] = EvpnArbitraryEsi(type_desc.Int9.from_user(esi)) if 'vni' in kwargs: # Disable to generate MPLS labels, because encapsulation type # is not MPLS. from ryu.services.protocols.bgp.api.prefix import ( TUNNEL_TYPE_VXLAN, TUNNEL_TYPE_NVGRE) assert tunnel_type in [TUNNEL_TYPE_VXLAN, TUNNEL_TYPE_NVGRE] gen_lbl = False prefix = subclass(**kwargs) else: raise BgpCoreError( desc='Unsupported route family %s' % route_family) # We do not check if we have a path to given prefix, we issue # withdrawal. Hence multiple withdrawals have not side effect. return vrf_table.insert_vrf_path( nlri=prefix, next_hop=next_hop, gen_lbl=gen_lbl, is_withdraw=is_withdraw, tunnel_type=tunnel_type)
def update_vrf_table(self, route_dist, prefix=None, next_hop=None, route_family=None, route_type=None, tunnel_type=None, is_withdraw=False, redundancy_mode=None, pmsi_tunnel_type=None, **kwargs): """Update a BGP route in the VRF table identified by `route_dist` with the given `next_hop`. If `is_withdraw` is False, which is the default, add a BGP route to the VRF table identified by `route_dist` with the given `next_hop`. If `is_withdraw` is True, remove a BGP route from the VRF table and the given `next_hop` is ignored. If `route_family` is VRF_RF_L2_EVPN, `route_type` and `kwargs` are required to construct EVPN NLRI and `prefix` is ignored. ``redundancy_mode`` specifies a redundancy mode type. ` `pmsi_tunnel_type` specifies the type of the PMSI tunnel attribute used to encode the multicast tunnel identifier. This field is advertised only if route_type is EVPN_MULTICAST_ETAG_ROUTE. Returns assigned VPN label. """ from ryu.services.protocols.bgp.core import BgpCoreError assert route_dist if is_withdraw: gen_lbl = False next_hop = None else: gen_lbl = True if not (is_valid_ipv4(next_hop) or is_valid_ipv6(next_hop)): raise BgpCoreError( desc='Invalid IPv4/IPv6 nexthop: %s' % next_hop) vrf_table = self._tables.get((route_dist, route_family)) if vrf_table is None: raise BgpCoreError( desc='VRF table does not exist: route_dist=%s, ' 'route_family=%s' % (route_dist, route_family)) vni = kwargs.get('vni', None) if route_family == VRF_RF_IPV4: if not is_valid_ipv4_prefix(prefix): raise BgpCoreError(desc='Invalid IPv4 prefix: %s' % prefix) ip, masklen = prefix.split('/') prefix = IPAddrPrefix(int(masklen), ip) elif route_family == VRF_RF_IPV6: if not is_valid_ipv6_prefix(prefix): raise BgpCoreError(desc='Invalid IPv6 prefix: %s' % prefix) ip6, masklen = prefix.split('/') prefix = IP6AddrPrefix(int(masklen), ip6) elif route_family == VRF_RF_L2_EVPN: assert route_type if route_type == EvpnMacIPAdvertisementNLRI.ROUTE_TYPE_NAME: # MPLS labels will be assigned automatically kwargs['mpls_labels'] = [] subclass = EvpnNLRI._lookup_type_name(route_type) kwargs['route_dist'] = route_dist esi = kwargs.get('esi', None) if esi is not None: if isinstance(esi, dict): esi_type = esi.get('type', 0) esi_class = EvpnEsi._lookup_type(esi_type) kwargs['esi'] = esi_class.from_jsondict(esi) else: # isinstance(esi, numbers.Integral) kwargs['esi'] = EvpnArbitraryEsi( type_desc.Int9.from_user(esi)) if vni is not None: # Disable to generate MPLS labels, # because encapsulation type is not MPLS. from ryu.services.protocols.bgp.api.prefix import ( TUNNEL_TYPE_VXLAN, TUNNEL_TYPE_NVGRE) assert tunnel_type in [ None, TUNNEL_TYPE_VXLAN, TUNNEL_TYPE_NVGRE] gen_lbl = False prefix = subclass(**kwargs) else: raise BgpCoreError( desc='Unsupported route family %s' % route_family) # We do not check if we have a path to given prefix, we issue # withdrawal. Hence multiple withdrawals have not side effect. return vrf_table.insert_vrf_path( nlri=prefix, next_hop=next_hop, gen_lbl=gen_lbl, is_withdraw=is_withdraw, redundancy_mode=redundancy_mode, vni=vni, tunnel_type=tunnel_type, pmsi_tunnel_type=pmsi_tunnel_type)