summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorISHIDA Wataru <ishida.wataru@lab.ntt.co.jp>2014-03-30 08:27:09 +0000
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2014-04-01 17:29:15 +0900
commit706cd11ce38093263e0e43792aef64ed60535395 (patch)
tree594baec965e339954d4994db47898638f706e4af
parentf813ec4232e610df45519d0ae73f3f83852f99cc (diff)
bgp: handle non-MPBGP UPDATE msg
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/base.py3
-rw-r--r--ryu/services/protocols/bgp/core_managers/table_manager.py24
-rw-r--r--ryu/services/protocols/bgp/info_base/ipv4.py71
-rw-r--r--ryu/services/protocols/bgp/peer.py151
-rw-r--r--ryu/services/protocols/bgp/rtconf/base.py9
-rw-r--r--ryu/services/protocols/bgp/rtconf/neighbors.py14
-rw-r--r--ryu/services/protocols/bgp/utils/bgp.py5
7 files changed, 267 insertions, 10 deletions
diff --git a/ryu/services/protocols/bgp/base.py b/ryu/services/protocols/bgp/base.py
index d68f1ad4..489ba3af 100644
--- a/ryu/services/protocols/bgp/base.py
+++ b/ryu/services/protocols/bgp/base.py
@@ -42,7 +42,8 @@ OrderedDict = OrderedDict
# Currently supported address families.
-SUPPORTED_GLOBAL_RF = set([nlri.RF_IPv4_VPN,
+SUPPORTED_GLOBAL_RF = set([nlri.RF_IPv4_UC,
+ nlri.RF_IPv4_VPN,
nlri.RF_RTC_UC,
nlri.RF_IPv6_VPN
])
diff --git a/ryu/services/protocols/bgp/core_managers/table_manager.py b/ryu/services/protocols/bgp/core_managers/table_manager.py
index 4aca4a8d..5554e4a1 100644
--- a/ryu/services/protocols/bgp/core_managers/table_manager.py
+++ b/ryu/services/protocols/bgp/core_managers/table_manager.py
@@ -2,6 +2,8 @@ import logging
from ryu.services.protocols.bgp.base import SUPPORTED_GLOBAL_RF
from ryu.services.protocols.bgp.info_base.rtc import RtcTable
+from ryu.services.protocols.bgp.info_base.ipv4 import Ipv4Path
+from ryu.services.protocols.bgp.info_base.ipv4 import Ipv4Table
from ryu.services.protocols.bgp.info_base.vpnv4 import Vpnv4Path
from ryu.services.protocols.bgp.info_base.vpnv4 import Vpnv4Table
from ryu.services.protocols.bgp.info_base.vpnv6 import Vpnv6Path
@@ -146,7 +148,10 @@ class TableCoreManager(object):
)
global_table = None
- if route_family == nlri.RF_IPv4_VPN:
+ if route_family == nlri.RF_IPv4_UC:
+ global_table = self.get_ipv4_table()
+
+ elif route_family == nlri.RF_IPv4_VPN:
global_table = self.get_vpn4_table()
elif route_family == nlri.RF_IPv6_VPN:
@@ -171,6 +176,23 @@ class TableCoreManager(object):
vrf_tables[(scope_id, table_id)] = table
return vrf_tables
+ def get_ipv4_table(self):
+ """Returns global IPv4 table.
+
+ Creates the table if it does not exist.
+ """
+
+ vpn_table = self._global_tables.get(nlri.RF_IPv4_UC)
+ # Lazy initialize the table.
+ if not vpn_table:
+ vpn_table = Ipv4Table(self._core_service, self._signal_bus)
+ self._global_tables[nlri.RF_IPv4_UC] = vpn_table
+ self._tables[(None, nlri.RF_IPv4_UC)] = vpn_table
+
+ return vpn_table
+
+
+
def get_vpn6_table(self):
"""Returns global VPNv6 table.
diff --git a/ryu/services/protocols/bgp/info_base/ipv4.py b/ryu/services/protocols/bgp/info_base/ipv4.py
new file mode 100644
index 00000000..0d8a68dc
--- /dev/null
+++ b/ryu/services/protocols/bgp/info_base/ipv4.py
@@ -0,0 +1,71 @@
+# Copyright (c) NTT Multimedia Communications Laboratories, Inc.
+# All rights reserved.
+
+"""
+ Defines data types and models required specifically for IPv4 support.
+"""
+
+import logging
+
+from ryu.services.protocols.bgp.protocols.bgp.nlri import Ipv4
+from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv4_UC
+
+from ryu.services.protocols.bgp.info_base.base import Path
+from ryu.services.protocols.bgp.info_base.base import Table
+from ryu.services.protocols.bgp.info_base.base import Destination
+from ryu.services.protocols.bgp.info_base.base import NonVrfPathProcessingMixin
+
+LOG = logging.getLogger('bgpspeaker.info_base.ipv4')
+
+
+class IPv4Dest(Destination, NonVrfPathProcessingMixin):
+ """VPNv4 Destination
+
+ Store IPv4 Paths.
+ """
+ ROUTE_FAMILY = RF_IPv4_UC
+
+ def _best_path_lost(self):
+ NonVrfPathProcessingMixin._best_path_lost(self)
+
+ def _new_best_path(self, best_path):
+ NonVrfPathProcessingMixin._new_best_path(self, best_path)
+
+class Ipv4Table(Table):
+ """Global table to store IPv4 routing information.
+
+ Uses `IPv4Dest` to store destination information for each known vpnv4
+ paths.
+ """
+ ROUTE_FAMILY = RF_IPv4_UC
+ VPN_DEST_CLASS = IPv4Dest
+
+ def __init__(self, core_service, signal_bus):
+ super(Ipv4Table, self).__init__(None, core_service, signal_bus)
+
+ def _table_key(self, nlri):
+ """Return a key that will uniquely identify this NLRI inside
+ this table.
+ """
+ return nlri.prefix
+
+ def _create_dest(self, nlri):
+ return self.VPN_DEST_CLASS(self, nlri)
+
+ def __str__(self):
+ return '%s(scope_id: %s, rf: %s)' % (
+ self.__class__.__name__, self.scope_id, self.route_family
+ )
+
+
+
+class Ipv4Path(Path):
+ """Represents a way of reaching an VPNv4 destination."""
+ ROUTE_FAMILY = RF_IPv4_UC
+ VRF_PATH_CLASS = None # defined in init - anti cyclic import hack
+ NLRI_CLASS = Ipv4
+
+ def __init__(self, *args, **kwargs):
+ super(Ipv4Path, self).__init__(*args, **kwargs)
+ from ryu.services.protocols.bgp.info_base.vrf4 import Vrf4Path
+ self.VRF_PATH_CLASS = Vrf4Path
diff --git a/ryu/services/protocols/bgp/peer.py b/ryu/services/protocols/bgp/peer.py
index 87838b39..2b41b62c 100644
--- a/ryu/services/protocols/bgp/peer.py
+++ b/ryu/services/protocols/bgp/peer.py
@@ -888,10 +888,37 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
mp_unreach_attr = update_msg.get_path_attr(
pathattr.MpUnreachNlri.ATTR_NAME
)
+
+ # non-MPBGP Update msg.
if not (mp_reach_attr or mp_unreach_attr):
- LOG.error('Received UPDATE msg. with no MpReachNlri or '
+ LOG.info('Received UPDATE msg. with no MpReachNlri or '
'MpUnReachNlri attribute.')
- raise exceptions.MalformedAttrList()
+ if not self.is_mpbgp_cap_valid(nlri.RF_IPv4_UC):
+ LOG.error('Got UPDATE message with un-available afi/safi %s' % nlri.RF_IPv4_UC)
+
+ nlri_list = update_msg.nlri_list
+ if len(nlri_list) > 0:
+ # Check for missing well-known mandatory attributes.
+ aspath = update_msg.get_path_attr(pathattr.AsPath.ATTR_NAME)
+ if not aspath:
+ raise exceptions.MissingWellKnown(pathattr.AsPath.TYPE_CODE)
+
+ # We do not have a setting to enable/disable first-as check.
+ # We by default do first-as check below.
+ if (self.is_ebgp_peer() and
+ not aspath.has_matching_leftmost(self.remote_as)):
+ LOG.error('First AS check fails. Raise appropriate exception.')
+ raise exceptions.MalformedAsPath()
+
+ origin = update_msg.get_path_attr(pathattr.Origin.ATTR_NAME)
+ if not origin:
+ raise exceptions.MissingWellKnown(pathattr.Origin.TYPE_CODE)
+
+ nexthop = update_msg.get_path_attr(pathattr.NextHop.ATTR_NAME)
+ if not nexthop:
+ raise exceptions.MissingWellKnown(pathattr.NextHop.TYPE_CODE)
+
+ return True
# Check if received MP_UNREACH path attribute is of available afi/safi
if mp_unreach_attr:
@@ -963,15 +990,127 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
mp_unreach_attr = update_msg.get_path_attr(
pathattr.MpUnreachNlri.ATTR_NAME
)
+
+ nlri_list = update_msg.nlri_list
+ withdraw_list = update_msg.withdraw_list
+
if mp_reach_attr:
# Extract advertised paths from given message.
- self._extract_and_handle_new_paths(update_msg)
+ self._extract_and_handle_mpbgp_new_paths(update_msg)
if mp_unreach_attr:
# Extract withdraws from given message.
- self._extract_and_handle_withdraws(mp_unreach_attr)
+ self._extract_and_handle_mpbgp_withdraws(mp_unreach_attr)
+
+ if nlri_list:
+ self._extract_and_handle_bgp4_new_paths(update_msg)
+
+ if withdraw_list:
+ self._extract_and_handle_bgp4_withdraws(withdraw_list)
+
+ def _extract_and_handle_bgp4_new_paths(self, update_msg):
+ """Extracts new paths advertised in the given update message's
+ *MpReachNlri* attribute.
+
+ Assumes MPBGP capability is enabled and message was validated.
+ Parameters:
+ - update_msg: (Update) is assumed to be checked for all bgp
+ message errors.
+ - valid_rts: (iterable) current valid/configured RTs.
+
+ Extracted paths are added to appropriate *Destination* for further
+ processing.
+ """
+ umsg_pattrs = update_msg.pathattr_map
+
+ msg_rf = nlri.RF_IPv4_UC
+ # Check if this route family is among supported route families.
+ if msg_rf not in SUPPORTED_GLOBAL_RF:
+ LOG.info(('Received route for route family %s which is'
+ ' not supported. Ignoring paths from this UPDATE: %s') %
+ (msg_rf, update_msg))
+ return
+
+ aspath = umsg_pattrs.get(pathattr.AsPath.ATTR_NAME)
+ # Check if AS_PATH has loops.
+ if aspath.has_local_as(self._common_conf.local_as):
+ LOG.error('Update message AS_PATH has loops. Ignoring this'
+ ' UPDATE. %s' % update_msg)
+ return
+
+ next_hop = update_msg.get_path_attr(pathattr.NextHop.ATTR_NAME)
+ # Nothing to do if we do not have any new NLRIs in this message.
+ msg_nlri_list = update_msg.nlri_list
+ if not msg_nlri_list:
+ LOG.debug('Update message did not have any new MP_REACH_NLRIs.')
+ return
+
+ # Create path instances for each NLRI from the update message.
+ for msg_nlri in msg_nlri_list:
+ LOG.debug('NLRI: %s' % msg_nlri)
+ new_path = bgp_utils.create_path(
+ self,
+ msg_nlri,
+ pattrs=umsg_pattrs,
+ 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)
+
+ # If update message had any qualifying new paths, do some book-keeping.
+ if msg_nlri_list:
+ # Update prefix statistics.
+ self.state.incr(PeerCounterNames.RECV_PREFIXES,
+ incr_by=len(msg_nlri_list))
+ # Check if we exceed max. prefixes allowed for this neighbor.
+ if self._neigh_conf.exceeds_max_prefix_allowed(
+ self.state.get_count(PeerCounterNames.RECV_PREFIXES)):
+ LOG.error('Max. prefix allowed for this neighbor '
+ 'exceeded.')
+
+ def _extract_and_handle_bgp4_withdraws(self, withdraw_list):
+ """Extracts withdraws advertised in the given update message's
+ *MpUnReachNlri* attribute.
+
+ Assumes MPBGP capability is enabled.
+ Parameters:
+ - update_msg: (Update) is assumed to be checked for all bgp
+ message errors.
+
+ Extracted withdraws are added to appropriate *Destination* for further
+ processing.
+ """
+ msg_rf = nlri.RF_IPv4_UC
+ # Check if this route family is among supported route families.
+ if msg_rf not in SUPPORTED_GLOBAL_RF:
+ LOG.info(
+ (
+ 'Received route for route family %s which is'
+ ' not supported. Ignoring withdraws form this UPDATE.'
+ ) % msg_rf
+ )
+ return
+
+ w_nlris = withdraw_list
+ if not w_nlris:
+ # If this is EOR of some kind, handle it
+ self._handle_eor(msg_rf)
+
+ for w_nlri in w_nlris:
+ w_path = bgp_utils.create_path(
+ self,
+ w_nlri,
+ is_withdraw=True
+ )
+ # Update appropriate table with withdraws.
+ tm = self._core_service.table_manager
+ tm.learn_path(w_path)
+
+
- def _extract_and_handle_new_paths(self, update_msg):
+ def _extract_and_handle_mpbgp_new_paths(self, update_msg):
"""Extracts new paths advertised in the given update message's
*MpReachNlri* attribute.
@@ -1066,7 +1205,7 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
LOG.error('Max. prefix allowed for this neighbor '
'exceeded.')
- def _extract_and_handle_withdraws(self, mp_unreach_attr):
+ def _extract_and_handle_mpbgp_withdraws(self, mp_unreach_attr):
"""Extracts withdraws advertised in the given update message's
*MpUnReachNlri* attribute.
diff --git a/ryu/services/protocols/bgp/rtconf/base.py b/ryu/services/protocols/bgp/rtconf/base.py
index 95717f8c..2fe0aa85 100644
--- a/ryu/services/protocols/bgp/rtconf/base.py
+++ b/ryu/services/protocols/bgp/rtconf/base.py
@@ -40,6 +40,7 @@ LOG = logging.getLogger('bgpspeaker.rtconf.base')
#
CAP_REFRESH = 'cap_refresh'
CAP_ENHANCED_REFRESH = 'cap_enhanced_refresh'
+CAP_MBGP_IPV4 = 'cap_mbgp_ipv4'
CAP_MBGP_VPNV4 = 'cap_mbgp_vpnv4'
CAP_MBGP_VPNV6 = 'cap_mbgp_vpnv6'
CAP_RTC = 'cap_rtc'
@@ -587,6 +588,14 @@ def validate_cap_enhanced_refresh(cer):
'settings: %s boolean value expected' % cer)
return cer
+@validate(name=CAP_MBGP_IPV4)
+def validate_cap_mbgp_ipv4(cmv4):
+ if cmv4 not in (True, False):
+ raise ConfigTypeError(desc='Invalid Enhanced Refresh capability '
+ 'settings: %s boolean value expected' % cmv4)
+
+ return cmv4
+
@validate(name=CAP_MBGP_VPNV4)
def validate_cap_mbgp_vpnv4(cmv4):
diff --git a/ryu/services/protocols/bgp/rtconf/neighbors.py b/ryu/services/protocols/bgp/rtconf/neighbors.py
index 679a1cb3..9a4920bd 100644
--- a/ryu/services/protocols/bgp/rtconf/neighbors.py
+++ b/ryu/services/protocols/bgp/rtconf/neighbors.py
@@ -24,6 +24,7 @@ from ryu.services.protocols.bgp.rtconf.base import ADVERTISE_PEER_AS
from ryu.services.protocols.bgp.rtconf.base import BaseConf
from ryu.services.protocols.bgp.rtconf.base import BaseConfListener
from ryu.services.protocols.bgp.rtconf.base import CAP_ENHANCED_REFRESH
+from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV4
from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV4
from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_VPNV6
from ryu.services.protocols.bgp.rtconf.base import CAP_REFRESH
@@ -51,6 +52,7 @@ from ryu.services.protocols.bgp.protocols.bgp.capabilities import \
MultiprotocolExtentionCap
from ryu.services.protocols.bgp.protocols.bgp.capabilities import \
RouteRefreshCap
+from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv4_UC
from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv4_VPN
from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv6_VPN
from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_RTC_UC
@@ -71,6 +73,7 @@ LOCAL_PORT = 'local_port'
DEFAULT_CAP_GR_NULL = True
DEFAULT_CAP_REFRESH = True
DEFAULT_CAP_ENHANCED_REFRESH = True
+DEFAULT_CAP_MBGP_IPV4 = False
DEFAULT_CAP_MBGP_VPNV4 = True
DEFAULT_CAP_MBGP_VPNV6 = False
DEFAULT_HOLD_TIME = 40
@@ -146,7 +149,7 @@ class NeighborConf(ConfWithId, ConfWithStats):
REQUIRED_SETTINGS = frozenset([REMOTE_AS, IP_ADDRESS, LOCAL_ADDRESS,
LOCAL_PORT])
OPTIONAL_SETTINGS = frozenset([CAP_REFRESH,
- CAP_ENHANCED_REFRESH, CAP_MBGP_VPNV4,
+ CAP_ENHANCED_REFRESH, CAP_MBGP_VPNV4, CAP_MBGP_IPV4,
CAP_MBGP_VPNV6, CAP_RTC, RTC_AS, HOLD_TIME,
ENABLED, MULTI_EXIT_DISC, MAX_PREFIXES,
ADVERTISE_PEER_AS, SITE_OF_ORIGINS])
@@ -159,6 +162,8 @@ class NeighborConf(ConfWithId, ConfWithStats):
CAP_REFRESH, DEFAULT_CAP_REFRESH, **kwargs)
self._settings[CAP_ENHANCED_REFRESH] = compute_optional_conf(
CAP_ENHANCED_REFRESH, DEFAULT_CAP_ENHANCED_REFRESH, **kwargs)
+ self._settings[CAP_MBGP_IPV4] = compute_optional_conf(
+ CAP_MBGP_IPV4, DEFAULT_CAP_MBGP_IPV4, **kwargs)
self._settings[CAP_MBGP_VPNV4] = compute_optional_conf(
CAP_MBGP_VPNV4, DEFAULT_CAP_MBGP_VPNV4, **kwargs)
self._settings[CAP_MBGP_VPNV6] = compute_optional_conf(
@@ -255,6 +260,10 @@ class NeighborConf(ConfWithId, ConfWithStats):
return self._settings[CAP_ENHANCED_REFRESH]
@property
+ def cap_mbgp_ipv4(self):
+ return self._settings[CAP_MBGP_IPV4]
+
+ @property
def cap_mbgp_vpnv4(self):
return self._settings[CAP_MBGP_VPNV4]
@@ -323,6 +332,9 @@ class NeighborConf(ConfWithId, ConfWithStats):
capabilities = OrderedDict()
mbgp_caps = []
+ if self.cap_mbgp_ipv4:
+ mbgp_caps.append(MultiprotocolExtentionCap(RF_IPv4_UC))
+
if self.cap_mbgp_vpnv4:
mbgp_caps.append(MultiprotocolExtentionCap(RF_IPv4_VPN))
diff --git a/ryu/services/protocols/bgp/utils/bgp.py b/ryu/services/protocols/bgp/utils/bgp.py
index bee4d3b9..fe22c45b 100644
--- a/ryu/services/protocols/bgp/utils/bgp.py
+++ b/ryu/services/protocols/bgp/utils/bgp.py
@@ -20,6 +20,7 @@ import logging
import socket
from ryu.services.protocols.bgp.protocols.bgp.messages import Update
+from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv4_UC
from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv4_VPN
from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_IPv6_VPN
from ryu.services.protocols.bgp.protocols.bgp.nlri import RF_RTC_UC
@@ -27,6 +28,7 @@ from ryu.services.protocols.bgp.protocols.bgp.nlri import RtNlri
from ryu.services.protocols.bgp.protocols.bgp import pathattr
from ryu.services.protocols.bgp.protocols.bgp.pathattr import Med
from ryu.services.protocols.bgp.info_base.rtc import RtcPath
+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
@@ -34,7 +36,8 @@ from ryu.services.protocols.bgp.info_base.vpnv6 import Vpnv6Path
LOG = logging.getLogger('utils.bgp')
# RouteFmaily to path sub-class mapping.
-_ROUTE_FAMILY_TO_PATH_MAP = {RF_IPv4_VPN: Vpnv4Path,
+_ROUTE_FAMILY_TO_PATH_MAP = {RF_IPv4_UC: Ipv4Path,
+ RF_IPv4_VPN: Vpnv4Path,
RF_IPv6_VPN: Vpnv6Path,
RF_RTC_UC: RtcPath}