bgp: local preference support IPv6, VPNv4/v6 route family

local preference supports IPv6 and VPNv4/v6 route family.
sorry, previous patch contains pep8 warnings, so I cleaned them.
Please discard previous one.

Signed-off-by: Hiroshi Yokoi <yokoi.hiroshi@po.ntts.co.jp>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
Hiroshi Yokoi 2014-09-18 21:23:55 +09:00 committed by FUJITA Tomonori
parent 0fff3fa73c
commit 594fb6a191
6 changed files with 121 additions and 33 deletions

View File

@ -29,6 +29,7 @@ from ryu.services.protocols.bgp.rtconf.vrfs import ROUTE_DISTINGUISHER
from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF
from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4 from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4
from ryu.services.protocols.bgp.rtconf.vrfs import VrfConf from ryu.services.protocols.bgp.rtconf.vrfs import VrfConf
from ryu.services.protocols.bgp import constants as const
LOG = logging.getLogger('bgpspeaker.api.rtconf') LOG = logging.getLogger('bgpspeaker.api.rtconf')
@ -152,22 +153,50 @@ def set_neighbor_in_filter(neigh_ip_address, filters):
@RegisterWithArgChecks(name='neighbor.attribute_map.set', @RegisterWithArgChecks(name='neighbor.attribute_map.set',
req_args=[neighbors.IP_ADDRESS, req_args=[neighbors.IP_ADDRESS,
neighbors.ATTRIBUTE_MAP]) neighbors.ATTRIBUTE_MAP],
def set_neighbor_attribute_map(neigh_ip_address, attribute_maps): opt_args=[ROUTE_DISTINGUISHER, VRF_RF])
"""Returns a neighbor attribute_map for given ip address if exists.""" def set_neighbor_attribute_map(neigh_ip_address, at_maps,
route_dist=None, route_family=VRF_RF_IPV4):
"""set attribute_maps to the neighbor."""
core = CORE_MANAGER.get_core_service() core = CORE_MANAGER.get_core_service()
peer = core.peer_manager.get_by_addr(neigh_ip_address) peer = core.peer_manager.get_by_addr(neigh_ip_address)
peer.attribute_maps = attribute_maps
at_maps_key = const.ATTR_MAPS_LABEL_DEFAULT
at_maps_dict = {}
if route_dist is not None:
vrf_conf =\
CORE_MANAGER.vrfs_conf.get_vrf_conf(route_dist, route_family)
if vrf_conf:
at_maps_key = ':'.join([route_dist, route_family])
else:
raise RuntimeConfigError(desc='No VrfConf with rd %s' %
route_dist)
at_maps_dict[const.ATTR_MAPS_LABEL_KEY] = at_maps_key
at_maps_dict[const.ATTR_MAPS_VALUE] = at_maps
peer.attribute_maps = at_maps_dict
return True return True
@RegisterWithArgChecks(name='neighbor.attribute_map.get', @RegisterWithArgChecks(name='neighbor.attribute_map.get',
req_args=[neighbors.IP_ADDRESS]) req_args=[neighbors.IP_ADDRESS],
def get_neighbor_attribute_map(neigh_ip_address): opt_args=[ROUTE_DISTINGUISHER, VRF_RF])
def get_neighbor_attribute_map(neigh_ip_address, route_dist=None,
route_family=VRF_RF_IPV4):
"""Returns a neighbor attribute_map for given ip address if exists.""" """Returns a neighbor attribute_map for given ip address if exists."""
core = CORE_MANAGER.get_core_service() core = CORE_MANAGER.get_core_service()
ret = core.peer_manager.get_by_addr(neigh_ip_address).attribute_maps peer = core.peer_manager.get_by_addr(neigh_ip_address)
return ret at_maps_key = const.ATTR_MAPS_LABEL_DEFAULT
if route_dist is not None:
at_maps_key = ':'.join([route_dist, route_family])
at_maps = peer.attribute_maps.get(at_maps_key)
if at_maps:
return at_maps.get(const.ATTR_MAPS_ORG_KEY)
else:
return []
# ============================================================================= # =============================================================================
# VRF configuration related APIs # VRF configuration related APIs

View File

@ -526,7 +526,8 @@ class BGPSpeaker(object):
param['port'] = port param['port'] = port
call(func_name, **param) call(func_name, **param)
def attribute_map_set(self, address, attribute_maps): def attribute_map_set(self, address, attribute_maps,
route_dist=None, route_family=RF_VPN_V4):
"""This method sets attribute mapping to a neighbor. """This method sets attribute mapping to a neighbor.
attribute mapping can be used when you want to apply attribute mapping can be used when you want to apply
attribute to BGPUpdate under specific conditions. attribute to BGPUpdate under specific conditions.
@ -537,6 +538,12 @@ class BGPSpeaker(object):
before paths are advertised. All the items in the list must before paths are advertised. All the items in the list must
be an instance of AttributeMap class be an instance of AttributeMap class
``route_dist`` specifies route dist in which attribute_maps
are added.
``route_family`` specifies route family of the VRF.
This parameter must be RF_VPN_V4 or RF_VPN_V6.
We can set AttributeMap to a neighbor as follows; We can set AttributeMap to a neighbor as follows;
pref_filter = PrefixFilter('192.168.103.0/30', pref_filter = PrefixFilter('192.168.103.0/30',
@ -549,24 +556,42 @@ class BGPSpeaker(object):
""" """
assert route_family in (RF_VPN_V4, RF_VPN_V6),\
'route_family must be RF_VPN_V4 or RF_VPN_V6'
func_name = 'neighbor.attribute_map.set' func_name = 'neighbor.attribute_map.set'
param = {} param = {}
param[neighbors.IP_ADDRESS] = address param[neighbors.IP_ADDRESS] = address
param[neighbors.ATTRIBUTE_MAP] = attribute_maps param[neighbors.ATTRIBUTE_MAP] = attribute_maps
if route_dist is not None:
param[vrfs.ROUTE_DISTINGUISHER] = route_dist
param[vrfs.VRF_RF] = route_family
call(func_name, **param) call(func_name, **param)
def attribute_map_get(self, address): def attribute_map_get(self, address, route_dist=None,
route_family=RF_VPN_V4):
"""This method gets in-bound filters of the specified neighbor. """This method gets in-bound filters of the specified neighbor.
``address`` specifies the IP address of the neighbor. ``address`` specifies the IP address of the neighbor.
``route_dist`` specifies route distinguisher that has attribute_maps.
``route_family`` specifies route family of the VRF.
This parameter must be RF_VPN_V4 or RF_VPN_V6.
Returns a list object containing an instance of AttributeMap Returns a list object containing an instance of AttributeMap
""" """
assert route_family in (RF_VPN_V4, RF_VPN_V6),\
'route_family must be RF_VPN_V4 or RF_VPN_V6'
func_name = 'neighbor.attribute_map.get' func_name = 'neighbor.attribute_map.get'
param = {} param = {}
param[neighbors.IP_ADDRESS] = address param[neighbors.IP_ADDRESS] = address
if route_dist is not None:
param[vrfs.ROUTE_DISTINGUISHER] = route_dist
param[vrfs.VRF_RF] = route_family
attribute_maps = call(func_name, **param) attribute_maps = call(func_name, **param)
return attribute_maps return attribute_maps

View File

@ -48,3 +48,9 @@ VRF_TABLE = 'vrf_table'
# RTC EOR timer default value # RTC EOR timer default value
# Time to wait for RTC-EOR, before we can send initial UPDATE as per RFC # Time to wait for RTC-EOR, before we can send initial UPDATE as per RFC
RTC_EOR_DEFAULT_TIME = 60 RTC_EOR_DEFAULT_TIME = 60
# Constants for AttributeMaps
ATTR_MAPS_ORG_KEY = '__orig'
ATTR_MAPS_LABEL_KEY = 'at_maps_key'
ATTR_MAPS_LABEL_DEFAULT = 'default'
ATTR_MAPS_VALUE = 'at_maps'

View File

@ -94,6 +94,14 @@ class ConfigurationManager(CommonConfListener, VrfsConfListener,
self._signal_bus.vrf_removed(vrf_conf.route_dist) self._signal_bus.vrf_removed(vrf_conf.route_dist)
# Remove AttributeMaps under the removed vrf
rd = vrf_conf.route_dist
rf = vrf_conf.route_family
peers = self._peer_manager.iterpeers
for peer in peers:
key = ':'.join([rd, rf])
peer.attribute_maps.pop(key, None)
def on_add_vrf_conf(self, evt): def on_add_vrf_conf(self, evt):
"""Event handler for new VrfConf. """Event handler for new VrfConf.

View File

@ -947,14 +947,14 @@ class PrefixFilter(Filter):
ge and le condition, ge and le condition,
this method returns True as the matching result. this method returns True as the matching result.
``prefix`` specifies the prefix. prefix must be string. ``path`` specifies the path that has prefix.
""" """
prefix = path.nlri nlri = path.nlri
result = False result = False
length = prefix.length length = nlri.length
net = netaddr.IPNetwork(prefix.formatted_nlri_str) net = netaddr.IPNetwork(nlri.prefix)
if net in self._network: if net in self._network:
if self._ge is None and self._le is None: if self._ge is None and self._le is None:

View File

@ -37,6 +37,9 @@ from ryu.services.protocols.bgp.rtconf.neighbors import NeighborConfListener
from ryu.services.protocols.bgp.signals.emit import BgpSignalBus from ryu.services.protocols.bgp.signals.emit import BgpSignalBus
from ryu.services.protocols.bgp.speaker import BgpProtocol from ryu.services.protocols.bgp.speaker import BgpProtocol
from ryu.services.protocols.bgp.info_base.ipv4 import Ipv4Path from ryu.services.protocols.bgp.info_base.ipv4 import Ipv4Path
from ryu.services.protocols.bgp.info_base.vpnv4 import Vpnv4Path
from ryu.services.protocols.bgp.info_base.vpnv6 import Vpnv6Path
from ryu.services.protocols.bgp.rtconf.vrfs import VRF_RF_IPV4, VRF_RF_IPV6
from ryu.services.protocols.bgp.utils import bgp as bgp_utils from ryu.services.protocols.bgp.utils import bgp as bgp_utils
from ryu.services.protocols.bgp.utils.evtlet import EventletIOFactory from ryu.services.protocols.bgp.utils.evtlet import EventletIOFactory
from ryu.services.protocols.bgp.utils import stats from ryu.services.protocols.bgp.utils import stats
@ -415,15 +418,18 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
@property @property
def attribute_maps(self): def attribute_maps(self):
return self._attribute_maps['__orig']\ return self._attribute_maps
if '__orig' in self._attribute_maps else []
@attribute_maps.setter @attribute_maps.setter
def attribute_maps(self, attribute_maps): def attribute_maps(self, attribute_maps):
_attr_maps = {} _attr_maps = {}
_attr_maps.setdefault('__orig', []) _attr_maps.setdefault(const.ATTR_MAPS_ORG_KEY, [])
for a in attribute_maps: # key is 'default' or rd_rf that represents RD and route_family
key = attribute_maps[const.ATTR_MAPS_LABEL_KEY]
at_maps = attribute_maps[const.ATTR_MAPS_VALUE]
for a in at_maps:
cloned = a.clone() cloned = a.clone()
LOG.debug("AttributeMap attr_type: %s, attr_value: %s", LOG.debug("AttributeMap attr_type: %s, attr_value: %s",
cloned.attr_type, cloned.attr_value) cloned.attr_type, cloned.attr_value)
@ -431,9 +437,9 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
attr_list.append(cloned) attr_list.append(cloned)
# preserve original order of attribute_maps # preserve original order of attribute_maps
_attr_maps['__orig'].append(cloned) _attr_maps[const.ATTR_MAPS_ORG_KEY].append(cloned)
self._attribute_maps = _attr_maps self._attribute_maps[key] = _attr_maps
self.on_update_attribute_maps() self.on_update_attribute_maps()
def is_mpbgp_cap_valid(self, route_family): def is_mpbgp_cap_valid(self, route_family):
@ -908,20 +914,19 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
# attribute_maps and set local-pref value. # attribute_maps and set local-pref value.
# If the path doesn't match, we set default local-pref 100. # If the path doesn't match, we set default local-pref 100.
localpref_attr = BGPPathAttributeLocalPref(100) localpref_attr = BGPPathAttributeLocalPref(100)
# TODO handle VPNv4Path key = const.ATTR_MAPS_LABEL_DEFAULT
if isinstance(path, Ipv4Path):
if AttributeMap.ATTR_LOCAL_PREF in self._attribute_maps:
maps = \
self._attribute_maps[AttributeMap.ATTR_LOCAL_PREF]
for m in maps:
cause, result = m.evaluate(path)
LOG.debug(
"local_pref evaluation result:%s, cause:%s",
result, cause)
if result: if isinstance(path, (Vpnv4Path, Vpnv6Path)):
localpref_attr = m.get_attribute() nlri = nlri_list[0]
break rf = VRF_RF_IPV4 if isinstance(path, Vpnv4Path)\
else VRF_RF_IPV6
key = ':'.join([nlri.route_dist, rf])
attr_type = AttributeMap.ATTR_LOCAL_PREF
at_maps = self._attribute_maps.get(key, {})
result = self._lookup_attribute_map(at_maps, attr_type, path)
if result:
localpref_attr = result
# COMMUNITY Attribute. # COMMUNITY Attribute.
community_attr = pathattr_map.get(BGP_ATTR_TYPE_COMMUNITIES) community_attr = pathattr_map.get(BGP_ATTR_TYPE_COMMUNITIES)
@ -1972,3 +1977,18 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
if self._neigh_conf.enabled: if self._neigh_conf.enabled:
if not self._connect_retry_event.is_set(): if not self._connect_retry_event.is_set():
self._connect_retry_event.set() self._connect_retry_event.set()
@staticmethod
def _lookup_attribute_map(attribute_map, attr_type, path):
result_attr = None
if attr_type in attribute_map:
maps = attribute_map[attr_type]
for m in maps:
cause, result = m.evaluate(path)
LOG.debug(
"local_pref evaluation result:%s, cause:%s",
result, cause)
if result:
result_attr = m.get_attribute()
break
return result_attr