mirror of
https://github.com/faucetsdn/ryu.git
synced 2026-05-05 12:26:11 +02:00
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:
parent
e8d81ab194
commit
b8a1f7b6dd
@ -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
|
||||
|
||||
@ -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]
|
||||
|
||||
@ -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.
|
||||
|
||||
@ -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]
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user