diff options
author | ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp> | 2014-07-28 18:22:57 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2014-07-28 19:14:56 +0900 |
commit | b8a1f7b6dd4c78d9ff83cfea18a506c6cafac646 (patch) | |
tree | acd8b9f121780cc70df4305235e2a6886723a34d | |
parent | e8d81ab194e99750186a1a08e6ab4adc1e4f494f (diff) |
bgp: add in-filter function
Signed-off-by: ISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>
Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r-- | ryu/services/protocols/bgp/api/rtconf.py | 9 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/bgpspeaker.py | 29 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/peer.py | 70 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/rtconf/neighbors.py | 27 |
4 files changed, 118 insertions, 17 deletions
diff --git a/ryu/services/protocols/bgp/api/rtconf.py b/ryu/services/protocols/bgp/api/rtconf.py index 6ddc66e4..13d90f0f 100644 --- a/ryu/services/protocols/bgp/api/rtconf.py +++ b/ryu/services/protocols/bgp/api/rtconf.py @@ -81,6 +81,9 @@ def update_neighbor(neigh_ip_address, changes): if k == neighbors.OUT_FILTER: rets.append(_update_outfilter(neigh_ip_address, v)) + if k == neighbors.IN_FILTER: + rets.append(_update_infilter(neigh_ip_address, v)) + return all(rets) @@ -91,6 +94,12 @@ def _update_med(neigh_ip_address, value): return True +def _update_infilter(neigh_ip_address, value): + neigh_conf = _get_neighbor_conf(neigh_ip_address) + neigh_conf.in_filter = value + return True + + def _update_outfilter(neigh_ip_address, value): neigh_conf = _get_neighbor_conf(neigh_ip_address) neigh_conf.out_filter = value diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py index 68f17347..e4aa3f00 100644 --- a/ryu/services/protocols/bgp/bgpspeaker.py +++ b/ryu/services/protocols/bgp/bgpspeaker.py @@ -53,12 +53,15 @@ from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV4 from ryu.services.protocols.bgp.rtconf.neighbors import DEFAULT_CAP_MBGP_VPNV6 from ryu.services.protocols.bgp.rtconf.neighbors import PEER_NEXT_HOP from ryu.services.protocols.bgp.rtconf.neighbors import PASSWORD +from ryu.services.protocols.bgp.rtconf.neighbors import IN_FILTER from ryu.services.protocols.bgp.rtconf.neighbors import OUT_FILTER from ryu.lib.packet.bgp import RF_IPv4_UC, RF_IPv6_UC OUT_FILTER_RF_IPv4_UC = RF_IPv4_UC OUT_FILTER_RF_IPv6_UC = RF_IPv6_UC +IN_FILTER_RF_IPv4_UC = RF_IPv4_UC +IN_FILTER_RF_IPv6_UC = RF_IPv6_UC NEIGHBOR_CONF_MED = 'multi_exit_disc' @@ -429,3 +432,29 @@ class BGPSpeaker(object): param[neighbors.IP_ADDRESS] = address settings = call(func_name, **param) return settings[OUT_FILTER] + + def in_filter_set(self, address, prefix_lists, + route_family=IN_FILTER_RF_IPv4_UC): + assert route_family in (IN_FILTER_RF_IPv4_UC, + IN_FILTER_RF_IPv6_UC),\ + "route family must be IPv4 or IPv6" + + if prefix_lists is None: + prefix_lists = [] + + func_name = 'neighbor.update' + prefix_value = {'prefix_lists': prefix_lists, + 'route_family': route_family} + filter_param = {neighbors.IN_FILTER: prefix_value} + + param = {} + param[neighbors.IP_ADDRESS] = address + param[neighbors.CHANGES] = filter_param + call(func_name, **param) + + def in_filter_get(self, address): + func_name = 'neighbor.get' + param = {} + param[neighbors.IP_ADDRESS] = address + settings = call(func_name, **param) + return settings[IN_FILTER] diff --git a/ryu/services/protocols/bgp/peer.py b/ryu/services/protocols/bgp/peer.py index 46ace748..5d5debec 100644 --- a/ryu/services/protocols/bgp/peer.py +++ b/ryu/services/protocols/bgp/peer.py @@ -1187,6 +1187,23 @@ class Peer(Source, Sink, NeighborConfListener, Activity): if withdraw_list: self._extract_and_handle_bgp4_withdraws(withdraw_list) + def _apply_in_filter(self, path): + block = False + blocked_cause = None + prefix_lists = self._neigh_conf.in_filter + + for prefix_list in prefix_lists: + policy, is_matched = prefix_list.evaluate(path) + if policy == PrefixList.POLICY_PERMIT and is_matched: + block = False + break + elif policy == PrefixList.POLICY_DENY and is_matched: + block = True + blocked_cause = prefix_list.prefix + ' - DENY' + break + + return block, blocked_cause + def _extract_and_handle_bgp4_new_paths(self, update_msg): """Extracts new paths advertised in the given update message's *MpReachNlri* attribute. @@ -1234,9 +1251,15 @@ class Peer(Source, Sink, NeighborConfListener, Activity): nexthop=next_hop ) LOG.debug('Extracted paths from Update msg.: %s' % new_path) - # Update appropriate table with new paths. - tm = self._core_service.table_manager - tm.learn_path(new_path) + + block, blocked_cause = self._apply_in_filter(new_path) + if not block: + # Update appropriate table with new paths. + tm = self._core_service.table_manager + tm.learn_path(new_path) + else: + LOG.debug('prefix : %s is blocked by in-bound filter : %s' + % (msg_nlri, blocked_cause)) # If update message had any qualifying new paths, do some book-keeping. if msg_nlri_list: @@ -1283,9 +1306,15 @@ class Peer(Source, Sink, NeighborConfListener, Activity): w_nlri, is_withdraw=True ) - # Update appropriate table with withdraws. - tm = self._core_service.table_manager - tm.learn_path(w_path) + + block, blocked_cause = self._apply_in_filter(w_path) + if block: + # Update appropriate table with withdraws. + tm = self._core_service.table_manager + tm.learn_path(w_path) + else: + LOG.debug('prefix : %s is blocked by in-bound filter : %s' + % (msg_nlri, blocked_cause)) def _extract_and_handle_mpbgp_new_paths(self, update_msg): """Extracts new paths advertised in the given update message's @@ -1363,13 +1392,19 @@ class Peer(Source, Sink, NeighborConfListener, Activity): nexthop=next_hop ) LOG.debug('Extracted paths from Update msg.: %s' % new_path) - if msg_rf == RF_RTC_UC \ - and self._init_rtc_nlri_path is not None: - self._init_rtc_nlri_path.append(new_path) + + block, blocked_cause = self._apply_in_filter(new_path) + if block: + if msg_rf == RF_RTC_UC \ + and self._init_rtc_nlri_path is not None: + self._init_rtc_nlri_path.append(new_path) + else: + # Update appropriate table with new paths. + tm = self._core_service.table_manager + tm.learn_path(new_path) else: - # Update appropriate table with new paths. - tm = self._core_service.table_manager - tm.learn_path(new_path) + LOG.debug('prefix : %s is blocked by in-bound filter : %s' + % (msg_nlri, blocked_cause)) # If update message had any qualifying new paths, do some book-keeping. if msg_nlri_list: @@ -1416,9 +1451,14 @@ class Peer(Source, Sink, NeighborConfListener, Activity): w_nlri, is_withdraw=True ) - # Update appropriate table with withdraws. - tm = self._core_service.table_manager - tm.learn_path(w_path) + block, blocked_cause = self._apply_in_filter(w_path) + if block: + # Update appropriate table with withdraws. + tm = self._core_service.table_manager + tm.learn_path(w_path) + else: + LOG.debug('prefix : %s is blocked by in-bound filter : %s' + % (w_nlri, blocked_cause)) def _handle_eor(self, route_family): """Currently we only handle EOR for RTC address-family. diff --git a/ryu/services/protocols/bgp/rtconf/neighbors.py b/ryu/services/protocols/bgp/rtconf/neighbors.py index 39b58e30..5b195ad7 100644 --- a/ryu/services/protocols/bgp/rtconf/neighbors.py +++ b/ryu/services/protocols/bgp/rtconf/neighbors.py @@ -74,6 +74,7 @@ LOCAL_ADDRESS = 'local_address' LOCAL_PORT = 'local_port' PEER_NEXT_HOP = 'next_hop' PASSWORD = 'password' +IN_FILTER = 'in_filter' OUT_FILTER = 'out_filter' # Default value constants. @@ -87,6 +88,7 @@ DEFAULT_CAP_MBGP_VPNV6 = False DEFAULT_HOLD_TIME = 40 DEFAULT_ENABLED = True DEFAULT_CAP_RTC = False +DEFAULT_IN_FILTER = [] DEFAULT_OUT_FILTER = [] # Default value for *MAX_PREFIXES* setting is set to 0. @@ -105,7 +107,7 @@ def validate_enabled(enabled): @validate(name=CHANGES) def validate_changes(changes): for k, v in changes.iteritems(): - if k not in (MULTI_EXIT_DISC, ENABLED, OUT_FILTER): + if k not in (MULTI_EXIT_DISC, ENABLED, IN_FILTER, OUT_FILTER): raise ConfigValueError(desc="Unknown field to change: %s" % k) if k == MULTI_EXIT_DISC: @@ -202,6 +204,11 @@ def valid_filter(filter_): return SUPPORTED_FILTER_VALIDATORS[filter_['type']](filter_) +@validate(name=IN_FILTER) +def validate_in_filters(filters): + return [valid_filter(filter_) for filter_ in filters] + + @validate(name=OUT_FILTER) def validate_out_filters(filters): return [valid_filter(filter_) for filter_ in filters] @@ -226,7 +233,7 @@ class NeighborConf(ConfWithId, ConfWithStats): ADVERTISE_PEER_AS, SITE_OF_ORIGINS, LOCAL_ADDRESS, LOCAL_PORT, PEER_NEXT_HOP, PASSWORD, - OUT_FILTER]) + IN_FILTER, OUT_FILTER]) def __init__(self, **kwargs): super(NeighborConf, self).__init__(**kwargs) @@ -252,6 +259,8 @@ class NeighborConf(ConfWithId, ConfWithStats): MAX_PREFIXES, DEFAULT_MAX_PREFIXES, **kwargs) self._settings[ADVERTISE_PEER_AS] = compute_optional_conf( ADVERTISE_PEER_AS, DEFAULT_ADVERTISE_PEER_AS, **kwargs) + self._settings[IN_FILTER] = compute_optional_conf( + IN_FILTER, DEFAULT_IN_FILTER, **kwargs) self._settings[OUT_FILTER] = compute_optional_conf( OUT_FILTER, DEFAULT_OUT_FILTER, **kwargs) @@ -421,6 +430,20 @@ class NeighborConf(ConfWithId, ConfWithStats): return self._settings[RTC_AS] @property + def in_filter(self): + return self._settings[IN_FILTER] + + @in_filter.setter + def in_filter(self, value): + self._settings[IN_FILTER] = [] + prefix_lists = value['prefix_lists'] + for prefix_list in prefix_lists: + # copy PrefixList object and put it in the _settings + self._settings[IN_FILTER].append(prefix_list.clone()) + + LOG.debug('set in-filter : %s' % prefix_lists) + + @property def out_filter(self): return self._settings[OUT_FILTER] |