Fix ipv6 transport failure caused by Ryu 4.9 and above
The api of neighbor_add has been changed in version 4.9 of Ryu. It will let ipv6 transport in neutron-dynamic-routing fail. In the previous version, a capability for address family is set automatically from result of parsing address parameter in Ryu. In the new version, the capability for ipv6 needs to be explicitly specified by enable_ipv6 parameter. This adds to parse an address in ryu driver in dragent. Depends-On: Iae040244fd38a8e2a8f6278b07334739e6700f1f Change-Id: I9eafc04a0a4ee651de0376f6cc98957a8a58eaf4
This commit is contained in:
parent
130861b86b
commit
9dc8c1afc2
|
@ -18,6 +18,8 @@ from oslo_utils import encodeutils
|
|||
from ryu.services.protocols.bgp import bgpspeaker
|
||||
from ryu.services.protocols.bgp.rtconf.neighbors import CONNECT_MODE_ACTIVE
|
||||
|
||||
from neutron_lib import constants as lib_consts
|
||||
|
||||
from neutron_dynamic_routing._i18n import _LE, _LI
|
||||
from neutron_dynamic_routing.services.bgp.agent.driver import base
|
||||
from neutron_dynamic_routing.services.bgp.agent.driver import exceptions as bgp_driver_exc # noqa
|
||||
|
@ -118,14 +120,22 @@ class RyuBgpDriver(base.BgpDriverBase):
|
|||
|
||||
# Validate peer_ip and peer_as.
|
||||
utils.validate_as_num('remote_as', peer_as)
|
||||
utils.validate_string(peer_ip)
|
||||
ip_version = utils.validate_ip_addr(peer_ip)
|
||||
utils.validate_auth(auth_type, password)
|
||||
if password is not None:
|
||||
password = encodeutils.to_utf8(password)
|
||||
|
||||
# Notify Ryu about BGP Peer addition
|
||||
if ip_version == lib_consts.IP_VERSION_4:
|
||||
enable_ipv4 = True
|
||||
enable_ipv6 = False
|
||||
else:
|
||||
enable_ipv4 = False
|
||||
enable_ipv6 = True
|
||||
curr_speaker.neighbor_add(address=peer_ip,
|
||||
remote_as=peer_as,
|
||||
enable_ipv4=enable_ipv4,
|
||||
enable_ipv6=enable_ipv6,
|
||||
password=password,
|
||||
connect_mode=CONNECT_MODE_ACTIVE)
|
||||
LOG.info(_LI('Added BGP Peer %(peer)s for remote_as=%(as)d to '
|
||||
|
@ -138,7 +148,7 @@ class RyuBgpDriver(base.BgpDriverBase):
|
|||
raise bgp_driver_exc.BgpSpeakerNotAdded(local_as=speaker_as,
|
||||
rtid=self.routerid)
|
||||
# Validate peer_ip. It must be a string.
|
||||
utils.validate_string(peer_ip)
|
||||
utils.validate_ip_addr(peer_ip)
|
||||
|
||||
# Notify Ryu about BGP Peer removal
|
||||
curr_speaker.neighbor_del(address=peer_ip)
|
||||
|
|
|
@ -13,8 +13,11 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
import netaddr
|
||||
import six
|
||||
|
||||
from neutron_lib import constants as lib_consts
|
||||
|
||||
from neutron_dynamic_routing.services.bgp.agent.driver import exceptions as bgp_driver_exc # noqa
|
||||
from neutron_dynamic_routing.services.bgp.common import constants as bgp_consts # noqa
|
||||
|
||||
|
@ -46,6 +49,16 @@ def validate_auth(auth_type, password):
|
|||
raise bgp_driver_exc.InvaildAuthType(auth_type=auth_type)
|
||||
|
||||
|
||||
def validate_ip_addr(ip_addr):
|
||||
if netaddr.valid_ipv4(ip_addr):
|
||||
return lib_consts.IP_VERSION_4
|
||||
elif netaddr.valid_ipv6(ip_addr):
|
||||
return lib_consts.IP_VERSION_6
|
||||
else:
|
||||
raise bgp_driver_exc.InvalidParamType(param=ip_addr,
|
||||
param_type='ip-address')
|
||||
|
||||
|
||||
def validate_string(param):
|
||||
if param is not None:
|
||||
if not isinstance(param, six.string_types):
|
||||
|
|
|
@ -35,6 +35,7 @@ FAKE_ROUTER_ID = '1.1.1.1'
|
|||
# Test variables for BGP Peer
|
||||
FAKE_PEER_AS = 45678
|
||||
FAKE_PEER_IP = '2.2.2.5'
|
||||
FAKE_PEER_IPV6 = '2001:db8::'
|
||||
FAKE_AUTH_TYPE = 'md5'
|
||||
FAKE_PEER_PASSWORD = 'awesome'
|
||||
|
||||
|
@ -85,6 +86,8 @@ class TestRyuBgpDriver(base.BaseTestCase):
|
|||
speaker.neighbor_add.assert_called_once_with(
|
||||
address=FAKE_PEER_IP,
|
||||
remote_as=FAKE_PEER_AS,
|
||||
enable_ipv4=True,
|
||||
enable_ipv6=False,
|
||||
password=None,
|
||||
connect_mode=CONNECT_MODE_ACTIVE)
|
||||
|
||||
|
@ -101,6 +104,8 @@ class TestRyuBgpDriver(base.BaseTestCase):
|
|||
speaker.neighbor_add.assert_called_once_with(
|
||||
address=FAKE_PEER_IP,
|
||||
remote_as=FAKE_PEER_AS,
|
||||
enable_ipv4=True,
|
||||
enable_ipv6=False,
|
||||
password=encodeutils.to_utf8(FAKE_PEER_PASSWORD),
|
||||
connect_mode=CONNECT_MODE_ACTIVE)
|
||||
|
||||
|
@ -119,9 +124,27 @@ class TestRyuBgpDriver(base.BaseTestCase):
|
|||
speaker.neighbor_add.assert_called_once_with(
|
||||
address=FAKE_PEER_IP,
|
||||
remote_as=FAKE_PEER_AS,
|
||||
enable_ipv4=True,
|
||||
enable_ipv6=False,
|
||||
password=encodeutils.to_utf8(NEW_FAKE_PEER_PASSWORD),
|
||||
connect_mode=CONNECT_MODE_ACTIVE)
|
||||
|
||||
def test_add_bgp_peer_with_ipv6(self):
|
||||
self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1)
|
||||
self.assertEqual(1,
|
||||
self.ryu_bgp_driver.cache.get_hosted_bgp_speakers_count())
|
||||
self.ryu_bgp_driver.add_bgp_peer(FAKE_LOCAL_AS1,
|
||||
FAKE_PEER_IPV6,
|
||||
FAKE_PEER_AS)
|
||||
speaker = self.ryu_bgp_driver.cache.get_bgp_speaker(FAKE_LOCAL_AS1)
|
||||
speaker.neighbor_add.assert_called_once_with(
|
||||
address=FAKE_PEER_IPV6,
|
||||
remote_as=FAKE_PEER_AS,
|
||||
enable_ipv4=False,
|
||||
enable_ipv6=True,
|
||||
password=None,
|
||||
connect_mode=CONNECT_MODE_ACTIVE)
|
||||
|
||||
def test_remove_bgp_peer(self):
|
||||
self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1)
|
||||
self.assertEqual(1,
|
||||
|
@ -201,6 +224,11 @@ class TestRyuBgpDriver(base.BaseTestCase):
|
|||
self.ryu_bgp_driver.add_bgp_peer,
|
||||
FAKE_LOCAL_AS1, FAKE_PEER_IP, FAKE_PEER_AS,
|
||||
FAKE_AUTH_TYPE, None)
|
||||
# Test with a invalid ip address
|
||||
self.assertRaises(bgp_driver_exc.InvalidParamType,
|
||||
self.ryu_bgp_driver.add_bgp_peer,
|
||||
FAKE_LOCAL_AS1, '1.2.3.a', FAKE_PEER_AS,
|
||||
FAKE_AUTH_TYPE, FAKE_PEER_PASSWORD)
|
||||
|
||||
def test_add_bgp_peer_with_invalid_asnum_range(self):
|
||||
self.ryu_bgp_driver.add_bgp_speaker(FAKE_LOCAL_AS1)
|
||||
|
|
|
@ -13,12 +13,139 @@
|
|||
# See the License for the specific language governing permissions and
|
||||
# limitations under the License.
|
||||
|
||||
from neutron_lib import constants as lib_consts
|
||||
|
||||
from neutron.tests import base
|
||||
|
||||
from neutron_dynamic_routing.services.bgp.agent.driver import exceptions as bgp_driver_exc # noqa
|
||||
from neutron_dynamic_routing.services.bgp.agent.driver import utils as bgp_driver_utils # noqa
|
||||
from neutron_dynamic_routing.services.bgp.common import constants as bgp_consts # noqa
|
||||
|
||||
FAKE_IP = '2.2.2.5'
|
||||
FAKE_IPV6 = '2001:db8::'
|
||||
FAKE_LOCAL_AS = 12345
|
||||
FAKE_RYU_SPEAKER = {}
|
||||
EXC_INV_PARAMTYPE = "Parameter %(param)s must be of %(param_type)s type."
|
||||
EXC_INV_PARAMRANGE = "%(param)s must be in %(range)s range."
|
||||
EXC_PASSWORD_NOTSPEC = "Password not specified for authentication " + \
|
||||
"type=%(auth_type)s."
|
||||
EXC_INV_AUTHTYPE = "Authentication type not supported. Requested " + \
|
||||
"type=%(auth_type)s."
|
||||
|
||||
|
||||
class TestValidateMethod(base.BaseTestCase):
|
||||
|
||||
def setUp(self):
|
||||
super(TestValidateMethod, self).setUp()
|
||||
|
||||
def test_validate_as_num_with_valid_as_num(self):
|
||||
self.assertIsNone(bgp_driver_utils.validate_as_num('local_as',
|
||||
64512))
|
||||
|
||||
def test_validate_as_num_with_string_as_num(self):
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.InvalidParamType,
|
||||
EXC_INV_PARAMTYPE % {'param': 'local_as',
|
||||
'param_type': 'integer'}):
|
||||
bgp_driver_utils.validate_as_num('local_as', '64512')
|
||||
|
||||
def test_validate_as_num_with_invalid_max_range(self):
|
||||
allowed_range = ('\[' +
|
||||
str(bgp_consts.MIN_ASNUM) + '-' +
|
||||
str(bgp_consts.MAX_ASNUM) +
|
||||
'\]')
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.InvalidParamRange,
|
||||
EXC_INV_PARAMRANGE % {'param': 'local_as',
|
||||
'range': allowed_range}):
|
||||
bgp_driver_utils.validate_as_num('local_as',
|
||||
bgp_consts.MAX_ASNUM + 1)
|
||||
|
||||
def test_validate_as_num_with_invalid_min_range(self):
|
||||
allowed_range = ('\[' +
|
||||
str(bgp_consts.MIN_ASNUM) + '-' +
|
||||
str(bgp_consts.MAX_ASNUM) +
|
||||
'\]')
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.InvalidParamRange,
|
||||
EXC_INV_PARAMRANGE % {'param': 'local_as',
|
||||
'range': allowed_range}):
|
||||
bgp_driver_utils.validate_as_num('local_as', 0)
|
||||
|
||||
def test_validate_auth_with_valid_auth_type(self):
|
||||
passwords = [None, 'password']
|
||||
for (auth_type, passwd) in zip(bgp_consts.SUPPORTED_AUTH_TYPES,
|
||||
passwords):
|
||||
self.assertIsNone(bgp_driver_utils.validate_auth(auth_type,
|
||||
passwd))
|
||||
|
||||
def test_validate_auth_with_integer_password(self):
|
||||
auth_type = bgp_consts.SUPPORTED_AUTH_TYPES[1]
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.InvalidParamType,
|
||||
EXC_INV_PARAMTYPE % {'param': '12345',
|
||||
'param_type': 'string'}):
|
||||
bgp_driver_utils.validate_auth(auth_type, 12345)
|
||||
|
||||
def test_validate_auth_with_invalid_auth_type(self):
|
||||
auth_type = 'abcde'
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.InvaildAuthType,
|
||||
EXC_INV_AUTHTYPE % {'auth_type': auth_type}):
|
||||
bgp_driver_utils.validate_auth(auth_type, 'password')
|
||||
|
||||
def test_validate_auth_with_not_none_auth_type_and_none_password(self):
|
||||
auth_type = bgp_consts.SUPPORTED_AUTH_TYPES[1]
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.PasswordNotSpecified,
|
||||
EXC_PASSWORD_NOTSPEC % {'auth_type': auth_type}):
|
||||
bgp_driver_utils.validate_auth(auth_type, None)
|
||||
|
||||
def test_validate_auth_with_none_auth_type_and_not_none_password(self):
|
||||
auth_type = None
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.InvaildAuthType,
|
||||
EXC_INV_AUTHTYPE % {'auth_type': auth_type}):
|
||||
bgp_driver_utils.validate_auth(auth_type, 'password')
|
||||
|
||||
def test_validate_ip_addr_with_ipv4_address(self):
|
||||
self.assertEqual(lib_consts.IP_VERSION_4,
|
||||
bgp_driver_utils.validate_ip_addr(FAKE_IP))
|
||||
|
||||
def test_validate_ip_addr_with_ipv6_address(self):
|
||||
self.assertEqual(lib_consts.IP_VERSION_6,
|
||||
bgp_driver_utils.validate_ip_addr(FAKE_IPV6))
|
||||
|
||||
def test_validate_ip_addr_with_integer_ip(self):
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.InvalidParamType,
|
||||
EXC_INV_PARAMTYPE % {'param': '12345',
|
||||
'param_type': 'ip-address'}):
|
||||
bgp_driver_utils.validate_ip_addr(12345)
|
||||
|
||||
def test_validate_ip_addr_with_invalid_ipv4_type(self):
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.InvalidParamType,
|
||||
EXC_INV_PARAMTYPE % {'param': '1.2.3.a',
|
||||
'param_type': 'ip-address'}):
|
||||
bgp_driver_utils.validate_ip_addr('1.2.3.a')
|
||||
|
||||
def test_validate_ip_addr_with_invalid_ipv6_type(self):
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.InvalidParamType,
|
||||
EXC_INV_PARAMTYPE % {'param': '2001:db8::ggg',
|
||||
'param_type': 'ip-address'}):
|
||||
bgp_driver_utils.validate_ip_addr('2001:db8::ggg')
|
||||
|
||||
def test_validate_string_with_string(self):
|
||||
self.assertIsNone(bgp_driver_utils.validate_string(FAKE_IP))
|
||||
|
||||
def test_validate_string_with_integer_param(self):
|
||||
with self.assertRaisesRegex(
|
||||
bgp_driver_exc.InvalidParamType,
|
||||
EXC_INV_PARAMTYPE % {'param': '12345',
|
||||
'param_type': 'string'}):
|
||||
bgp_driver_utils.validate_string(12345)
|
||||
|
||||
|
||||
class TestBgpMultiSpeakerCache(base.BaseTestCase):
|
||||
|
|
Loading…
Reference in New Issue