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>
This commit is contained in:
ISHIDA Wataru 2014-07-28 18:22:57 +09:00 committed by FUJITA Tomonori
parent e8d81ab194
commit b8a1f7b6dd
4 changed files with 118 additions and 17 deletions

View File

@ -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

View File

@ -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]

View File

@ -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.

View File

@ -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)
@ -420,6 +429,20 @@ class NeighborConf(ConfWithId, ConfWithStats):
def rtc_as(self):
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]