mirror of
https://github.com/faucetsdn/ryu.git
synced 2026-05-10 14:56:11 +02:00
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:
parent
0ab9f19d60
commit
f2e62c2f2b
@ -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
|
||||
|
||||
@ -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
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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)
|
||||
|
||||
|
||||
85
ryu/services/protocols/bgp/info_base/ipv6.py
Normal file
85
ryu/services/protocols/bgp/info_base/ipv6.py
Normal 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
|
||||
@ -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):
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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):
|
||||
|
||||
@ -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(
|
||||
|
||||
@ -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}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user