diff options
author | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2014-06-29 20:55:44 +0900 |
---|---|---|
committer | FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp> | 2014-06-30 12:24:41 +0900 |
commit | f2e62c2f2b9b957f5ce3c28a94a974f356edda71 (patch) | |
tree | e4aaa3deca31952212f33ad8a2ceb6dbc158ee10 | |
parent | 0ab9f19d609f33ed7189dbdafa54c2b7508fbee3 (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.py | 4 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/base.py | 1 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/bgpspeaker.py | 19 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/core_managers/table_manager.py | 38 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/info_base/ipv6.py | 85 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/operator/commands/show/rib.py | 2 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/peer.py | 2 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/rtconf/base.py | 10 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/rtconf/neighbors.py | 18 | ||||
-rw-r--r-- | ryu/services/protocols/bgp/utils/bgp.py | 3 |
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} |