summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2014-06-29 20:55:44 +0900
committerFUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>2014-06-30 12:24:41 +0900
commitf2e62c2f2b9b957f5ce3c28a94a974f356edda71 (patch)
treee4aaa3deca31952212f33ad8a2ceb6dbc158ee10
parent0ab9f19d609f33ed7189dbdafa54c2b7508fbee3 (diff)
bgp: add IPv6 advertisement support
You can advertize IPv6 addresses to IPv6 neighbors. Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
-rw-r--r--ryu/services/protocols/bgp/api/rtconf.py4
-rw-r--r--ryu/services/protocols/bgp/base.py1
-rw-r--r--ryu/services/protocols/bgp/bgpspeaker.py19
-rw-r--r--ryu/services/protocols/bgp/core_managers/table_manager.py38
-rw-r--r--ryu/services/protocols/bgp/info_base/ipv6.py85
-rw-r--r--ryu/services/protocols/bgp/operator/commands/show/rib.py2
-rw-r--r--ryu/services/protocols/bgp/peer.py2
-rw-r--r--ryu/services/protocols/bgp/rtconf/base.py10
-rw-r--r--ryu/services/protocols/bgp/rtconf/neighbors.py18
-rw-r--r--ryu/services/protocols/bgp/utils/bgp.py3
10 files changed, 165 insertions, 17 deletions
diff --git a/ryu/services/protocols/bgp/api/rtconf.py b/ryu/services/protocols/bgp/api/rtconf.py
index 2869da5e..93eeb18e 100644
--- a/ryu/services/protocols/bgp/api/rtconf.py
+++ b/ryu/services/protocols/bgp/api/rtconf.py
@@ -176,12 +176,12 @@ def get_vrfs_conf():
@register(name='network.add')
def add_network(prefix):
tm = CORE_MANAGER.get_core_service().table_manager
- tm.add_to_ipv4_global_table(prefix)
+ tm.add_to_global_table(prefix)
return True
@register(name='network.del')
def del_network(prefix):
tm = CORE_MANAGER.get_core_service().table_manager
- tm.add_to_ipv4_global_table(prefix, is_withdraw=True)
+ tm.add_to_global_table(prefix, is_withdraw=True)
return True
diff --git a/ryu/services/protocols/bgp/base.py b/ryu/services/protocols/bgp/base.py
index 28ae2864..e0338c26 100644
--- a/ryu/services/protocols/bgp/base.py
+++ b/ryu/services/protocols/bgp/base.py
@@ -49,6 +49,7 @@ OrderedDict = OrderedDict
# Currently supported address families.
SUPPORTED_GLOBAL_RF = set([RF_IPv4_UC,
+ RF_IPv6_UC,
RF_IPv4_VPN,
RF_RTC_UC,
RF_IPv6_VPN
diff --git a/ryu/services/protocols/bgp/bgpspeaker.py b/ryu/services/protocols/bgp/bgpspeaker.py
index 8e33e85e..5b5cb96d 100644
--- a/ryu/services/protocols/bgp/bgpspeaker.py
+++ b/ryu/services/protocols/bgp/bgpspeaker.py
@@ -16,6 +16,7 @@
"""
+import netaddr
from ryu.lib import hub
from ryu.base import app_manager
from ryu.services.protocols.bgp.operator import ssh
@@ -43,6 +44,7 @@ from ryu.services.protocols.bgp.rtconf.common import LABEL_RANGE
from ryu.services.protocols.bgp.rtconf import neighbors
from ryu.services.protocols.bgp.rtconf import vrfs
from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV4
+from ryu.services.protocols.bgp.rtconf.base import CAP_MBGP_IPV6
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.neighbors import DEFAULT_CAP_MBGP_IPV4
@@ -188,9 +190,20 @@ class BGPSpeaker(object):
bgp_neighbor = {}
bgp_neighbor[neighbors.IP_ADDRESS] = address
bgp_neighbor[neighbors.REMOTE_AS] = remote_as
- bgp_neighbor[CAP_MBGP_IPV4] = enable_ipv4
- bgp_neighbor[CAP_MBGP_VPNV4] = enable_vpnv4
- bgp_neighbor[CAP_MBGP_VPNV6] = enable_vpnv6
+ # v6 advertizement is available with only v6 peering
+ if netaddr.valid_ipv4(address):
+ bgp_neighbor[CAP_MBGP_IPV4] = enable_ipv4
+ bgp_neighbor[CAP_MBGP_IPV6] = False
+ bgp_neighbor[CAP_MBGP_VPNV4] = enable_vpnv4
+ bgp_neighbor[CAP_MBGP_VPNV6] = enable_vpnv6
+ elif netaddr.valid_ipv6(address):
+ bgp_neighbor[CAP_MBGP_IPV4] = False
+ bgp_neighbor[CAP_MBGP_IPV6] = True
+ bgp_neighbor[CAP_MBGP_VPNV4] = False
+ bgp_neighbor[CAP_MBGP_VPNV6] = False
+ else:
+ # FIXME: should raise an exception
+ pass
call('neighbor.create', **bgp_neighbor)
def neighbor_del(self, address):
diff --git a/ryu/services/protocols/bgp/core_managers/table_manager.py b/ryu/services/protocols/bgp/core_managers/table_manager.py
index f8265dd7..a4aad997 100644
--- a/ryu/services/protocols/bgp/core_managers/table_manager.py
+++ b/ryu/services/protocols/bgp/core_managers/table_manager.py
@@ -1,10 +1,13 @@
import logging
+import netaddr
from collections import OrderedDict
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.ipv6 import Ipv6Path
+from ryu.services.protocols.bgp.info_base.ipv6 import Ipv6Table
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
@@ -164,7 +167,8 @@ class TableCoreManager(object):
global_table = None
if route_family == RF_IPv4_UC:
global_table = self.get_ipv4_table()
-
+ elif route_family == RF_IPv6_UC:
+ global_table = self.get_ipv6_table()
elif route_family == RF_IPv4_VPN:
global_table = self.get_vpn4_table()
@@ -205,6 +209,14 @@ class TableCoreManager(object):
return vpn_table
+ def get_ipv6_table(self):
+ table = self._global_tables.get(RF_IPv6_UC)
+ if not table:
+ table = Ipv6Table(self._core_service, self._signal_bus)
+ self._global_tables[RF_IPv6_UC] = table
+ self._tables[(None, RF_IPv6_UC)] = table
+ return table
+
def get_vpn6_table(self):
"""Returns global VPNv6 table.
@@ -483,13 +495,10 @@ class TableCoreManager(object):
gen_lbl=True
)
- def add_to_ipv4_global_table(self, prefix, is_withdraw=False):
- ip, masklen = prefix.split('/')
- _nlri = IPAddrPrefix(int(masklen), ip)
+ def add_to_global_table(self, prefix, is_withdraw=False):
src_ver_num = 1
peer = None
# set mandatory path attributes
- nexthop = '0.0.0.0'
origin = BGPPathAttributeOrigin(BGP_ATTR_ORIGIN_IGP)
aspath = BGPPathAttributeAsPath([[]])
@@ -497,9 +506,22 @@ class TableCoreManager(object):
pathattrs[BGP_ATTR_TYPE_ORIGIN] = origin
pathattrs[BGP_ATTR_TYPE_AS_PATH] = aspath
- new_path = Ipv4Path(peer, _nlri, src_ver_num,
- pattrs=pathattrs, nexthop=nexthop,
- is_withdraw=is_withdraw)
+ net = netaddr.IPNetwork(prefix)
+ ip = str(net.ip)
+ masklen = net.prefixlen
+ if netaddr.valid_ipv4(ip):
+ _nlri = IPAddrPrefix(masklen, ip)
+ nexthop = '0.0.0.0'
+ p = Ipv4Path
+ else:
+ _nlri = IP6AddrPrefix(masklen, ip)
+ nexthop = '::'
+ p = Ipv6Path
+
+ new_path = p(peer, _nlri, src_ver_num,
+ pattrs=pathattrs, nexthop=nexthop,
+ is_withdraw=is_withdraw)
+
# add to global ipv4 table and propagates to neighbors
self.learn_path(new_path)
diff --git a/ryu/services/protocols/bgp/info_base/ipv6.py b/ryu/services/protocols/bgp/info_base/ipv6.py
new file mode 100644
index 00000000..670f9964
--- /dev/null
+++ b/ryu/services/protocols/bgp/info_base/ipv6.py
@@ -0,0 +1,85 @@
+# Copyright (C) 2014 Nippon Telegraph and Telephone Corporation.
+#
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+# implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
+"""
+ Defines data types and models required specifically for IPv4 support.
+"""
+
+import logging
+
+from ryu.lib.packet.bgp import IPAddrPrefix
+from ryu.lib.packet.bgp import RF_IPv6_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.ipv6')
+
+
+class IPv6Dest(Destination, NonVrfPathProcessingMixin):
+ """v6 Destination
+
+ Store IPv6 Paths.
+ """
+ ROUTE_FAMILY = RF_IPv6_UC
+
+ def _best_path_lost(self):
+ old_best_path = self._best_path
+ NonVrfPathProcessingMixin._best_path_lost(self)
+ self._core_service._signal_bus.best_path_changed(old_best_path)
+
+ def _new_best_path(self, best_path):
+ NonVrfPathProcessingMixin._new_best_path(self, best_path)
+ self._core_service._signal_bus.best_path_changed(best_path)
+
+
+class Ipv6Table(Table):
+ """Global table to store IPv4 routing information.
+
+ Uses `IPv6Dest` to store destination information for each known vpnv6
+ paths.
+ """
+ ROUTE_FAMILY = RF_IPv6_UC
+ VPN_DEST_CLASS = IPv6Dest
+
+ def __init__(self, core_service, signal_bus):
+ super(Ipv6Table, 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 Ipv6Path(Path):
+ """Represents a way of reaching an v6 destination."""
+ ROUTE_FAMILY = RF_IPv6_UC
+ VRF_PATH_CLASS = None # defined in init - anti cyclic import hack
+ NLRI_CLASS = IPAddrPrefix
+
+ def __init__(self, *args, **kwargs):
+ super(Ipv6Path, self).__init__(*args, **kwargs)
+ from ryu.services.protocols.bgp.info_base.vrf6 import Vrf6Path
+ self.VRF_PATH_CLASS = Vrf6Path
diff --git a/ryu/services/protocols/bgp/operator/commands/show/rib.py b/ryu/services/protocols/bgp/operator/commands/show/rib.py
index 94e16574..d5077d05 100644
--- a/ryu/services/protocols/bgp/operator/commands/show/rib.py
+++ b/ryu/services/protocols/bgp/operator/commands/show/rib.py
@@ -11,7 +11,7 @@ from ryu.services.protocols.bgp.operator.commands.responses import \
class RibBase(Command, RouteFormatterMixin):
- supported_families = ['ipv4', 'vpnv4', 'rtfilter', 'vpnv6']
+ supported_families = ['ipv4', 'ipv6', 'vpnv4', 'rtfilter', 'vpnv6']
class Rib(RibBase):
diff --git a/ryu/services/protocols/bgp/peer.py b/ryu/services/protocols/bgp/peer.py
index 853473ec..70e36683 100644
--- a/ryu/services/protocols/bgp/peer.py
+++ b/ryu/services/protocols/bgp/peer.py
@@ -1233,7 +1233,7 @@ class Peer(Source, Sink, NeighborConfListener, Activity):
' UPDATE. %s' % update_msg)
return
- if msg_rf in (RF_IPv4_VPN, RF_IPv6_UC):
+ if msg_rf in (RF_IPv4_VPN, RF_IPv6_VPN):
# Check if we have Extended Communities Attribute.
# TODO(PH): Check if RT_NLRI afi/safi will ever have this attribute
ext_comm_attr = umsg_pattrs.get(BGP_ATTR_TYPE_EXTENDED_COMMUNITIES)
diff --git a/ryu/services/protocols/bgp/rtconf/base.py b/ryu/services/protocols/bgp/rtconf/base.py
index 154dcca0..271dab63 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_IPV6 = 'cap_mbgp_ipv6'
CAP_MBGP_VPNV4 = 'cap_mbgp_vpnv4'
CAP_MBGP_VPNV6 = 'cap_mbgp_vpnv6'
CAP_RTC = 'cap_rtc'
@@ -597,6 +598,15 @@ def validate_cap_mbgp_ipv4(cmv4):
return cmv4
+@validate(name=CAP_MBGP_IPV6)
+def validate_cap_mbgp_ipv4(cmv6):
+ if cmv6 not in (True, False):
+ raise ConfigTypeError(desc='Invalid Enhanced Refresh capability '
+ 'settings: %s boolean value expected' % cmv4)
+
+ return cmv6
+
+
@validate(name=CAP_MBGP_VPNV4)
def validate_cap_mbgp_vpnv4(cmv4):
if cmv4 not in (True, False):
diff --git a/ryu/services/protocols/bgp/rtconf/neighbors.py b/ryu/services/protocols/bgp/rtconf/neighbors.py
index 8e981058..8d97cee6 100644
--- a/ryu/services/protocols/bgp/rtconf/neighbors.py
+++ b/ryu/services/protocols/bgp/rtconf/neighbors.py
@@ -38,6 +38,7 @@ 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_IPV6
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
@@ -76,6 +77,7 @@ DEFAULT_CAP_GR_NULL = True
DEFAULT_CAP_REFRESH = True
DEFAULT_CAP_ENHANCED_REFRESH = False
DEFAULT_CAP_MBGP_IPV4 = True
+DEFAULT_CAP_MBGP_IPV6 = False
DEFAULT_CAP_MBGP_VPNV4 = False
DEFAULT_CAP_MBGP_VPNV6 = False
DEFAULT_HOLD_TIME = 40
@@ -156,8 +158,9 @@ class NeighborConf(ConfWithId, ConfWithStats):
VALID_EVT = frozenset([UPDATE_ENABLED_EVT, UPDATE_MED_EVT])
REQUIRED_SETTINGS = frozenset([REMOTE_AS, IP_ADDRESS])
OPTIONAL_SETTINGS = frozenset([CAP_REFRESH,
- CAP_ENHANCED_REFRESH, CAP_MBGP_VPNV4,
- CAP_MBGP_IPV4, CAP_MBGP_VPNV6,
+ CAP_ENHANCED_REFRESH,
+ CAP_MBGP_IPV4, CAP_MBGP_IPV6,
+ CAP_MBGP_VPNV4, CAP_MBGP_VPNV6,
CAP_RTC, RTC_AS, HOLD_TIME,
ENABLED, MULTI_EXIT_DISC, MAX_PREFIXES,
ADVERTISE_PEER_AS, SITE_OF_ORIGINS,
@@ -173,6 +176,8 @@ class NeighborConf(ConfWithId, ConfWithStats):
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_IPV6] = compute_optional_conf(
+ CAP_MBGP_IPV6, DEFAULT_CAP_MBGP_IPV6, **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(
@@ -281,6 +286,10 @@ class NeighborConf(ConfWithId, ConfWithStats):
return self._settings[CAP_MBGP_IPV4]
@property
+ def cap_mbgp_ipv6(self):
+ return self._settings[CAP_MBGP_IPV6]
+
+ @property
def cap_mbgp_vpnv4(self):
return self._settings[CAP_MBGP_VPNV4]
@@ -354,6 +363,11 @@ class NeighborConf(ConfWithId, ConfWithStats):
BGPOptParamCapabilityMultiprotocol(
RF_IPv4_UC.afi, RF_IPv4_UC.safi))
+ if self.cap_mbgp_ipv6:
+ mbgp_caps.append(
+ BGPOptParamCapabilityMultiprotocol(
+ RF_IPv6_UC.afi, RF_IPv6_UC.safi))
+
if self.cap_mbgp_vpnv4:
mbgp_caps.append(
BGPOptParamCapabilityMultiprotocol(
diff --git a/ryu/services/protocols/bgp/utils/bgp.py b/ryu/services/protocols/bgp/utils/bgp.py
index 4e7391be..95bcd265 100644
--- a/ryu/services/protocols/bgp/utils/bgp.py
+++ b/ryu/services/protocols/bgp/utils/bgp.py
@@ -21,6 +21,7 @@ import socket
from ryu.lib.packet.bgp import BGPUpdate
from ryu.lib.packet.bgp import RF_IPv4_UC
+from ryu.lib.packet.bgp import RF_IPv6_UC
from ryu.lib.packet.bgp import RF_IPv4_VPN
from ryu.lib.packet.bgp import RF_IPv6_VPN
from ryu.lib.packet.bgp import RF_RTC_UC
@@ -31,6 +32,7 @@ from ryu.lib.packet.bgp import BGPPathAttributeMpUnreachNLRI
from ryu.lib.packet.bgp import BGPPathAttributeUnknown
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.ipv6 import Ipv6Path
from ryu.services.protocols.bgp.info_base.vpnv4 import Vpnv4Path
from ryu.services.protocols.bgp.info_base.vpnv6 import Vpnv6Path
@@ -39,6 +41,7 @@ LOG = logging.getLogger('utils.bgp')
# RouteFmaily to path sub-class mapping.
_ROUTE_FAMILY_TO_PATH_MAP = {RF_IPv4_UC: Ipv4Path,
+ RF_IPv6_UC: Ipv6Path,
RF_IPv4_VPN: Vpnv4Path,
RF_IPv6_VPN: Vpnv6Path,
RF_RTC_UC: RtcPath}