From 594fb6a191a30256d21c332ea41c6ddbcc201fac Mon Sep 17 00:00:00 2001 From: Hiroshi Yokoi Date: Thu, 18 Sep 2014 21:23:55 +0900 Subject: 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 Signed-off-by: FUJITA Tomonori --- ryu/services/protocols/bgp/api/rtconf.py | 45 +++++++++++++--- ryu/services/protocols/bgp/bgpspeaker.py | 29 ++++++++++- ryu/services/protocols/bgp/constants.py | 6 +++ .../bgp/core_managers/configuration_manager.py | 8 +++ ryu/services/protocols/bgp/info_base/base.py | 8 +-- ryu/services/protocols/bgp/peer.py | 60 ++++++++++++++-------- 6 files changed, 122 insertions(+), 34 deletions(-) diff --git a/ryu/services/protocols/bgp/api/rtconf.py b/ryu/services/protocols/bgp/api/rtconf.py index ce989037..079a2f52 100644 --- a/ryu/services/protocols/bgp/api/rtconf.py +++ b/ryu/services/protocols/bgp/api/rtconf.py @@ -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_IPV4 from ryu.services.protocols.bgp.rtconf.vrfs import VrfConf +from ryu.services.protocols.bgp import constants as const 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', req_args=[neighbors.IP_ADDRESS, - neighbors.ATTRIBUTE_MAP]) -def set_neighbor_attribute_map(neigh_ip_address, attribute_maps): - """Returns a neighbor attribute_map for given ip address if exists.""" + neighbors.ATTRIBUTE_MAP], + opt_args=[ROUTE_DISTINGUISHER, VRF_RF]) +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() 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 @RegisterWithArgChecks(name='neighbor.attribute_map.get', - req_args=[neighbors.IP_ADDRESS]) -def get_neighbor_attribute_map(neigh_ip_address): + req_args=[neighbors.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.""" core = CORE_MANAGER.get_core_service() - ret = core.peer_manager.get_by_addr(neigh_ip_address).attribute_maps - return ret + peer = core.peer_manager.get_by_addr(neigh_ip_address) + 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 diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py index 9844e087..59e781ce 100644 --- a/ryu/services/protocols/bgp/bgpspeaker.py +++ b/ryu/services/protocols/bgp/bgpspeaker.py @@ -526,7 +526,8 @@ class BGPSpeaker(object): param['port'] = port 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. attribute mapping can be used when you want to apply attribute to BGPUpdate under specific conditions. @@ -537,6 +538,12 @@ class BGPSpeaker(object): before paths are advertised. All the items in the list must 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; 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' param = {} param[neighbors.IP_ADDRESS] = address 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) - 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. ``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 """ + 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' param = {} 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) return attribute_maps diff --git a/ryu/services/protocols/bgp/constants.py b/ryu/services/protocols/bgp/constants.py index b1af9b0a..bda55f05 100644 --- a/ryu/services/protocols/bgp/constants.py +++ b/ryu/services/protocols/bgp/constants.py @@ -48,3 +48,9 @@ VRF_TABLE = 'vrf_table' # RTC EOR timer default value # Time to wait for RTC-EOR, before we can send initial UPDATE as per RFC 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' diff --git a/ryu/services/protocols/bgp/core_managers/configuration_manager.py b/ryu/services/protocols/bgp/core_managers/configuration_manager.py index ffac9bcd..ff3dd3be 100644 --- a/ryu/services/protocols/bgp/core_managers/configuration_manager.py +++ b/ryu/services/protocols/bgp/core_managers/configuration_manager.py @@ -94,6 +94,14 @@ class ConfigurationManager(CommonConfListener, VrfsConfListener, 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): """Event handler for new VrfConf. diff --git a/ryu/services/protocols/bgp/info_base/base.py b/ryu/services/protocols/bgp/info_base/base.py index 13f02caf..0e56bd07 100644 --- a/ryu/services/protocols/bgp/info_base/base.py +++ b/ryu/services/protocols/bgp/info_base/base.py @@ -947,14 +947,14 @@ class PrefixFilter(Filter): ge and le condition, 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 - length = prefix.length - net = netaddr.IPNetwork(prefix.formatted_nlri_str) + length = nlri.length + net = netaddr.IPNetwork(nlri.prefix) if net in self._network: if self._ge is None and self._le is None: diff --git a/ryu/services/protocols/bgp/peer.py b/ryu/services/protocols/bgp/peer.py index 14618521..598e5936 100644 --- a/ryu/services/protocols/bgp/peer.py +++ b/ryu/services/protocols/bgp/peer.py @@ -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.speaker import BgpProtocol 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.evtlet import EventletIOFactory from ryu.services.protocols.bgp.utils import stats @@ -415,15 +418,18 @@ class Peer(Source, Sink, NeighborConfListener, Activity): @property def attribute_maps(self): - return self._attribute_maps['__orig']\ - if '__orig' in self._attribute_maps else [] + return self._attribute_maps @attribute_maps.setter def attribute_maps(self, attribute_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() LOG.debug("AttributeMap attr_type: %s, attr_value: %s", cloned.attr_type, cloned.attr_value) @@ -431,9 +437,9 @@ class Peer(Source, Sink, NeighborConfListener, Activity): attr_list.append(cloned) # 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() 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. # If the path doesn't match, we set default local-pref 100. localpref_attr = BGPPathAttributeLocalPref(100) - # TODO handle VPNv4Path - 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: - localpref_attr = m.get_attribute() - break + key = const.ATTR_MAPS_LABEL_DEFAULT + + if isinstance(path, (Vpnv4Path, Vpnv6Path)): + nlri = nlri_list[0] + 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_attr = pathattr_map.get(BGP_ATTR_TYPE_COMMUNITIES) @@ -1972,3 +1977,18 @@ class Peer(Source, Sink, NeighborConfListener, Activity): if self._neigh_conf.enabled: if not self._connect_retry_event.is_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 -- cgit v1.2.3