def __init__(self, labels, route_disc, prefix): Nlri.__init__(self) if not labels: labels = [] # Validate given params for label in labels: if not is_valid_mpls_label(label): raise ValueError('Invalid label %s' % label) if (not is_valid_route_disc(route_disc) or not is_valid_ipv6_prefix(prefix)): raise ValueError('Invalid parameter value(s).') self._labels = labels self._route_disc = route_disc self._prefix = prefix
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 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 is_valid_ip_prefix(prefix): if not (validation.is_valid_ipv4_prefix(prefix) or validation.is_valid_ipv6_prefix(prefix)): raise ConfigValueError(conf_name=IP_PREFIX, conf_value=prefix)
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)
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 is_valid_prefix(prefix): if not (validation.is_valid_ipv4_prefix(prefix) or validation.is_valid_ipv6_prefix(prefix)): raise ConfigValueError(conf_name=PREFIX, conf_value=prefix)
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 test_is_valid_ipv6_prefix_invalid_addr(self): eq_(False, validation.is_valid_ipv6_prefix("xxxx::xxxx/64"))
def test_is_valid_ipv6_prefix_without_prefix(self): eq_(False, validation.is_valid_ipv6_prefix("fe80::0011:aabb:ccdd:eeff"))
def test_is_valid_ipv6_prefix_not_str(self): eq_(False, validation.is_valid_ipv6_prefix(1234))
def test_is_valid_ipv6_prefix(self): ok_(validation.is_valid_ipv6_prefix("fe80::0011:aabb:ccdd:eeff/64"))
def __init__(self, prefix): if not is_valid_ipv6_prefix(prefix): raise ValueError('Invalid prefix %s.' % prefix) Nlri.__init__(self) self._prefix = prefix