summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>2014-07-28 18:22:57 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2014-07-28 19:14:56 +0900
commitb8a1f7b6dd4c78d9ff83cfea18a506c6cafac646 (patch)
treeacd8b9f121780cc70df4305235e2a6886723a34d
parente8d81ab194e99750186a1a08e6ab4adc1e4f494f (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.py9
-rw-r--r--ryu/services/protocols/bgp/bgpspeaker.py29
-rw-r--r--ryu/services/protocols/bgp/peer.py70
-rw-r--r--ryu/services/protocols/bgp/rtconf/neighbors.py27
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]