bgp: add IPv6 advertisement support

You can advertize IPv6 addresses to IPv6 neighbors.

Signed-off-by: FUJITA Tomonori <fujita.tomonori@lab.ntt.co.jp>
This commit is contained in:
FUJITA Tomonori 2014-06-29 20:55:44 +09:00
parent 0ab9f19d60
commit f2e62c2f2b
10 changed files with 165 additions and 17 deletions

View File

@ -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

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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

View File

@ -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):

View File

@ -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)

View File

@ -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):

View File

@ -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(
@ -280,6 +285,10 @@ class NeighborConf(ConfWithId, ConfWithStats):
def cap_mbgp_ipv4(self):
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(

View File

@ -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}