def update_flowspec_vrf_table(self, flowspec_family, route_dist, rules, actions=None, is_withdraw=False): """Update a BGP route in the VRF table for Flow Specification. ``flowspec_family`` specifies one of the flowspec family name. ``route_dist`` specifies a route distinguisher value. ``rules`` specifies NLRIs of Flow Specification as a dictionary type value. `` actions`` specifies Traffic Filtering Actions of Flow Specification as a dictionary type value. If `is_withdraw` is False, which is the default, add a BGP route to the VRF table identified by `route_dist`. If `is_withdraw` is True, remove a BGP route from the VRF table. """ from ryu.services.protocols.bgp.core import BgpCoreError from ryu.services.protocols.bgp.api.prefix import ( FLOWSPEC_FAMILY_VPNV4, FLOWSPEC_FAMILY_VPNV6, FLOWSPEC_FAMILY_L2VPN, ) if flowspec_family == FLOWSPEC_FAMILY_VPNV4: vrf_table = self._tables.get((route_dist, VRF_RF_IPV4_FLOWSPEC)) prefix = FlowSpecIPv4NLRI.from_user(**rules) try: communities = create_v4flowspec_actions(actions) except ValueError as e: raise BgpCoreError(desc=str(e)) elif flowspec_family == FLOWSPEC_FAMILY_VPNV6: vrf_table = self._tables.get((route_dist, VRF_RF_IPV6_FLOWSPEC)) prefix = FlowSpecIPv6NLRI.from_user(**rules) try: communities = create_v6flowspec_actions(actions) except ValueError as e: raise BgpCoreError(desc=str(e)) elif flowspec_family == FLOWSPEC_FAMILY_L2VPN: vrf_table = self._tables.get((route_dist, VRF_RF_L2VPN_FLOWSPEC)) prefix = FlowSpecL2VPNNLRI.from_user(route_dist, **rules) try: communities = create_l2vpnflowspec_actions(actions) except ValueError as e: raise BgpCoreError(desc=str(e)) else: raise BgpCoreError( desc='Unsupported flowspec_family %s' % flowspec_family) if vrf_table is None: raise BgpCoreError( desc='VRF table does not exist: route_dist=%s, ' 'flowspec_family=%s' % (route_dist, flowspec_family)) # We do not check if we have a path to given prefix, we issue # withdrawal. Hence multiple withdrawals have not side effect. vrf_table.insert_vrffs_path( nlri=prefix, communities=communities, is_withdraw=is_withdraw)
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) prefix = nlri.Ipv4(prefix) 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) prefix = nlri.Ipv6(prefix) # 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 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.') prefix = nlri.Ipv4(prefix) 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.') prefix = nlri.Ipv6(prefix) return vrf_table.insert_vrf_path( prefix, next_hop=next_hop, gen_lbl=True )
def update_flowspec_global_table(self, flowspec_family, rules, actions=None, is_withdraw=False): """Update a BGP route in the Global table for Flow Specification. ``flowspec_family`` specifies one of the Flow Specification family name. ``rules`` specifies NLRIs of Flow Specification as a dictionary type value. `` actions`` specifies Traffic Filtering Actions of Flow Specification as a dictionary type value. 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. """ from ryu.services.protocols.bgp.core import BgpCoreError from ryu.services.protocols.bgp.api.prefix import FLOWSPEC_FAMILY_IPV4 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 if flowspec_family == FLOWSPEC_FAMILY_IPV4: _nlri = FlowSpecIPv4NLRI.from_user(**rules) p = IPv4FlowSpecPath try: communities = create_v4flowspec_actions(actions) except ValueError as e: raise BgpCoreError(desc=str(e)) if communities: pathattrs[BGP_ATTR_TYPE_EXTENDED_COMMUNITIES] = ( BGPPathAttributeExtendedCommunities( communities=communities)) else: raise BgpCoreError(desc='Unsupported flowspec family %s' % flowspec_family) new_path = p(peer, _nlri, src_ver_num, pattrs=pathattrs, 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)