tests: implement ipaddress convenience methods
Add vpp specific properties to ip addresses for use in the api. .vapi_af -- returns [ADDRESS_IP4, ADDRESS_IP6] .vapi_af_name -- returns the string ['ip4', 'ip6'] Update tests to demonstrate usage. Type: feature Change-Id: I43447a1522769d99f89debdc714c51700068d771 Signed-off-by: Paul Vinciguerra <pvinci@vinciconsulting.com>
This commit is contained in:
@ -41,7 +41,7 @@ enum ip_neighbor_flags: u8
|
||||
|
||||
/** \brief IP neighbor
|
||||
@param sw_if_index - interface used to reach neighbor
|
||||
@param flags - flags for the nieghbor
|
||||
@param flags - flags for the neighbor
|
||||
@param mac_address - l2 address of the neighbor
|
||||
@param ip_address - ip4 or ip6 address of the neighbor
|
||||
*/
|
||||
@ -56,7 +56,7 @@ typedef ip_neighbor {
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param is_add - 1 to add neighbor, 0 to delete
|
||||
@param neighbor - the neighor to add/remove
|
||||
@param neighbor - the neighbor to add/remove
|
||||
*/
|
||||
define ip_neighbor_add_del
|
||||
{
|
||||
@ -70,7 +70,7 @@ define ip_neighbor_add_del
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param retval - return value
|
||||
@param stats_index - the index to use for this neighbor in the stats segement
|
||||
@param stats_index - the index to use for this neighbor in the stats segment
|
||||
*/
|
||||
define ip_neighbor_add_del_reply
|
||||
{
|
||||
@ -79,10 +79,10 @@ define ip_neighbor_add_del_reply
|
||||
u32 stats_index;
|
||||
};
|
||||
|
||||
/** \brief Dump IP neighboors
|
||||
/** \brief Dump IP neighbors
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
@param sw_if_index - the interface to dump neighboors, ~0 == all
|
||||
@param sw_if_index - the interface to dump neighbors, ~0 == all
|
||||
@param af - address family is ipv[6|4]
|
||||
*/
|
||||
define ip_neighbor_dump
|
||||
@ -93,7 +93,7 @@ define ip_neighbor_dump
|
||||
vl_api_address_family_t af;
|
||||
};
|
||||
|
||||
/** \brief IP neighboors dump response
|
||||
/** \brief IP neighbors dump response
|
||||
@param context - sender context which was passed in the request
|
||||
@param age - time between last update and sending this message, in seconds
|
||||
@param neighbour - the neighbor
|
||||
@ -132,7 +132,7 @@ autoreply define ip_neighbor_config
|
||||
has a different set of neighbours it than VPP
|
||||
currently has. The CP would thus like to 'replace' VPP's set
|
||||
only by specifying what the new set shall be, i.e. it is not
|
||||
going to delete anything that already eixts, rather, is wants any
|
||||
going to delete anything that already exists, rather, it wants any
|
||||
unspecified neighbors deleted implicitly.
|
||||
The CP declares the start of this procedure with this replace_begin
|
||||
API Call, and when it has populated all neighbours it wants, it calls
|
||||
@ -163,7 +163,7 @@ autoreply define ip_neighbor_replace_end
|
||||
u32 context;
|
||||
};
|
||||
|
||||
/** \brief Register for IP4 ARP resolution event on receing ARP reply or
|
||||
/** \brief Register for IP4 ARP resolution event on receiving ARP reply or
|
||||
MAC/IP info from ARP requests in L2 BDs
|
||||
@param client_index - opaque cookie to identify the sender
|
||||
@param context - sender context, to match reply w/ request
|
||||
|
@ -27,6 +27,11 @@ except NameError:
|
||||
ADDRESS_IP4 = 0
|
||||
ADDRESS_IP6 = 1
|
||||
|
||||
|
||||
def verify_enum_hint(e):
|
||||
return (e.ADDRESS_IP4.value == ADDRESS_IP4) and\
|
||||
(e.ADDRESS_IP6.value == ADDRESS_IP6)
|
||||
|
||||
#
|
||||
# Type conversion for input arguments and return values
|
||||
#
|
||||
|
@ -17,6 +17,7 @@
|
||||
from __future__ import print_function
|
||||
from __future__ import absolute_import
|
||||
import ctypes
|
||||
import ipaddress
|
||||
import sys
|
||||
import multiprocessing as mp
|
||||
import os
|
||||
@ -28,6 +29,7 @@ import fnmatch
|
||||
import weakref
|
||||
import atexit
|
||||
import time
|
||||
from . vpp_format import verify_enum_hint
|
||||
from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType
|
||||
from . vpp_serializer import VPPMessage, vpp_get_type, VPPTypeAlias
|
||||
|
||||
@ -77,6 +79,26 @@ else:
|
||||
return d.items()
|
||||
|
||||
|
||||
def add_convenience_methods():
|
||||
# provide convenience methods to IP[46]Address.vapi_af
|
||||
def _vapi_af(self):
|
||||
if 6 == self._version:
|
||||
return VppEnum.vl_api_address_family_t.ADDRESS_IP6.value
|
||||
if 4 == self._version:
|
||||
return VppEnum.vl_api_address_family_t.ADDRESS_IP4.value
|
||||
raise ValueError("Invalid _version.")
|
||||
|
||||
def _vapi_af_name(self):
|
||||
if 6 == self._version:
|
||||
return 'ip6'
|
||||
if 4 == self._version:
|
||||
return 'ip4'
|
||||
raise ValueError("Invalid _version.")
|
||||
|
||||
ipaddress._IPAddressBase.vapi_af = property(_vapi_af)
|
||||
ipaddress._IPAddressBase.vapi_af_name = property(_vapi_af_name)
|
||||
|
||||
|
||||
class VppApiDynamicMethodHolder(object):
|
||||
pass
|
||||
|
||||
@ -113,6 +135,7 @@ class VPPRuntimeError(RuntimeError):
|
||||
class VPPValueError(ValueError):
|
||||
pass
|
||||
|
||||
|
||||
class VPPApiJSONFiles(object):
|
||||
@classmethod
|
||||
def find_api_dir(cls, dirs):
|
||||
@ -295,6 +318,7 @@ class VPPApiJSONFiles(object):
|
||||
self.logger.error('Not implemented error for {}'.format(m[0]))
|
||||
return messages, services
|
||||
|
||||
|
||||
class VPPApiClient(object):
|
||||
"""VPP interface.
|
||||
|
||||
@ -383,16 +407,20 @@ class VPPApiClient(object):
|
||||
# Basic sanity check
|
||||
if len(self.messages) == 0 and not testmode:
|
||||
raise VPPValueError(1, 'Missing JSON message definitions')
|
||||
if not(verify_enum_hint(VppEnum.vl_api_address_family_t)):
|
||||
raise VPPRuntimeError("Invalid address family hints. "
|
||||
"Cannot continue.")
|
||||
|
||||
self.transport = VppTransport(self, read_timeout=read_timeout,
|
||||
server_address=server_address)
|
||||
# Make sure we allow VPP to clean up the message rings.
|
||||
atexit.register(vpp_atexit, weakref.ref(self))
|
||||
|
||||
add_convenience_methods()
|
||||
|
||||
def get_function(self, name):
|
||||
return getattr(self._api, name)
|
||||
|
||||
|
||||
class ContextId(object):
|
||||
"""Multiprocessing-safe provider of unique context IDs."""
|
||||
def __init__(self):
|
||||
|
@ -582,9 +582,12 @@ class VppTestCase(unittest.TestCase):
|
||||
"VPP-API connection failed, did you forget "
|
||||
"to 'continue' VPP from within gdb?", RED))
|
||||
raise
|
||||
except vpp_papi.VPPRuntimeError as e:
|
||||
cls.logger.debug("%s" % e)
|
||||
cls.quit()
|
||||
raise
|
||||
except Exception as e:
|
||||
cls.logger.debug("Exception connecting to VPP: %s" % e)
|
||||
|
||||
cls.quit()
|
||||
raise
|
||||
|
||||
|
@ -93,29 +93,16 @@ class VppIpMPrefix():
|
||||
'same address family.')
|
||||
|
||||
def encode(self):
|
||||
if 6 == self.version:
|
||||
prefix = {
|
||||
'af': VppEnum.vl_api_address_family_t.ADDRESS_IP6,
|
||||
'grp_address': {
|
||||
'ip6': self.gaddr
|
||||
},
|
||||
'src_address': {
|
||||
'ip6': self.saddr
|
||||
},
|
||||
'grp_address_length': self.glen,
|
||||
}
|
||||
else:
|
||||
prefix = {
|
||||
'af': VppEnum.vl_api_address_family_t.ADDRESS_IP4,
|
||||
'grp_address': {
|
||||
'ip4': self.gaddr
|
||||
},
|
||||
'src_address': {
|
||||
'ip4': self.saddr
|
||||
},
|
||||
'grp_address_length': self.glen,
|
||||
}
|
||||
return prefix
|
||||
return {
|
||||
'af': ip_address(self.gaddr).vapi_af,
|
||||
'grp_address': {
|
||||
ip_address(self.gaddr).vapi_af_name: self.gaddr
|
||||
},
|
||||
'src_address': {
|
||||
ip_address(self.saddr).vapi_af_name: self.saddr
|
||||
},
|
||||
'grp_address_length': self.glen,
|
||||
}
|
||||
|
||||
@property
|
||||
def length(self):
|
||||
@ -145,6 +132,4 @@ class VppIpMPrefix():
|
||||
return (self.glen == other.grp_address_length and
|
||||
self.gaddr == str(other.grp_address.ip6) and
|
||||
self.saddr == str(other.src_address.ip6))
|
||||
raise Exception("Comparing VppIpMPrefix:%s with unknown type: %s" %
|
||||
(self, other))
|
||||
return False
|
||||
return NotImplemented
|
||||
|
@ -639,41 +639,39 @@ class VppIpMRoute(VppObject):
|
||||
for path in self.paths:
|
||||
self.encoded_paths.append(path.encode())
|
||||
|
||||
def encode(self, paths=None):
|
||||
_paths = self.encoded_paths if paths is None else paths
|
||||
return {'table_id': self.table_id,
|
||||
'entry_flags': self.e_flags,
|
||||
'rpf_id': self.rpf_id,
|
||||
'prefix': self.prefix.encode(),
|
||||
'n_paths': len(_paths),
|
||||
'paths': _paths,
|
||||
}
|
||||
|
||||
def add_vpp_config(self):
|
||||
r = self._test.vapi.ip_mroute_add_del(self.table_id,
|
||||
self.prefix.encode(),
|
||||
self.e_flags,
|
||||
self.rpf_id,
|
||||
self.encoded_paths,
|
||||
r = self._test.vapi.ip_mroute_add_del(route=self.encode(),
|
||||
is_multipath=1,
|
||||
is_add=1)
|
||||
self.stats_index = r.stats_index
|
||||
self._test.registry.register(self, self._test.logger)
|
||||
return self
|
||||
|
||||
def remove_vpp_config(self):
|
||||
self._test.vapi.ip_mroute_add_del(self.table_id,
|
||||
self.prefix.encode(),
|
||||
self.e_flags,
|
||||
self.rpf_id,
|
||||
self.encoded_paths,
|
||||
self._test.vapi.ip_mroute_add_del(route=self.encode(),
|
||||
is_multipath=1,
|
||||
is_add=0)
|
||||
|
||||
def update_entry_flags(self, flags):
|
||||
self.e_flags = flags
|
||||
self._test.vapi.ip_mroute_add_del(self.table_id,
|
||||
self.prefix.encode(),
|
||||
self.e_flags,
|
||||
self.rpf_id,
|
||||
[],
|
||||
self._test.vapi.ip_mroute_add_del(route=self.encode(paths=[]),
|
||||
is_multipath=1,
|
||||
is_add=1)
|
||||
|
||||
def update_rpf_id(self, rpf_id):
|
||||
self.rpf_id = rpf_id
|
||||
self._test.vapi.ip_mroute_add_del(self.table_id,
|
||||
self.prefix.encode(),
|
||||
self.e_flags,
|
||||
self.rpf_id,
|
||||
[],
|
||||
self._test.vapi.ip_mroute_add_del(route=self.encode(paths=[]),
|
||||
is_multipath=1,
|
||||
is_add=1)
|
||||
|
||||
def update_path_flags(self, itf, flags):
|
||||
@ -683,13 +681,11 @@ class VppIpMRoute(VppObject):
|
||||
self.encoded_paths[p] = self.paths[p].encode()
|
||||
break
|
||||
|
||||
self._test.vapi.ip_mroute_add_del(self.table_id,
|
||||
self.prefix.encode(),
|
||||
self.e_flags,
|
||||
self.rpf_id,
|
||||
[self.encoded_paths[p]],
|
||||
is_add=1,
|
||||
is_multipath=0)
|
||||
self._test.vapi.ip_mroute_add_del(
|
||||
route=self.encode(
|
||||
paths=[self.encoded_paths[p]]),
|
||||
is_add=1,
|
||||
is_multipath=0)
|
||||
|
||||
def query_vpp_config(self):
|
||||
return find_mroute(self._test,
|
||||
|
@ -16,11 +16,8 @@ except NameError:
|
||||
def find_nbr(test, sw_if_index, nbr_addr, is_static=0, mac=None):
|
||||
ip_addr = ip_address(text_type(nbr_addr))
|
||||
e = VppEnum.vl_api_ip_neighbor_flags_t
|
||||
if 6 == ip_addr.version:
|
||||
af = VppEnum.vl_api_address_family_t.ADDRESS_IP6
|
||||
else:
|
||||
af = VppEnum.vl_api_address_family_t.ADDRESS_IP4
|
||||
nbrs = test.vapi.ip_neighbor_dump(sw_if_index=sw_if_index, af=af)
|
||||
nbrs = test.vapi.ip_neighbor_dump(sw_if_index=sw_if_index,
|
||||
af=ip_addr.vapi_af)
|
||||
|
||||
for n in nbrs:
|
||||
if ip_addr == n.neighbor.ip_address and \
|
||||
|
@ -675,32 +675,6 @@ class VppPapiProvider(object):
|
||||
'udp_checksum': udp_checksum,
|
||||
})
|
||||
|
||||
def ip_mroute_add_del(self,
|
||||
table_id,
|
||||
prefix,
|
||||
e_flags,
|
||||
rpf_id,
|
||||
paths,
|
||||
is_add=1,
|
||||
is_multipath=1):
|
||||
"""
|
||||
IP Multicast Route add/del
|
||||
"""
|
||||
return self.api(
|
||||
self.papi.ip_mroute_add_del,
|
||||
{
|
||||
'is_add': is_add,
|
||||
'is_multipath': is_multipath,
|
||||
'route': {
|
||||
'table_id': table_id,
|
||||
'entry_flags': e_flags,
|
||||
'rpf_id': rpf_id,
|
||||
'prefix': prefix,
|
||||
'n_paths': len(paths),
|
||||
'paths': paths,
|
||||
}
|
||||
})
|
||||
|
||||
def mfib_signal_dump(self):
|
||||
return self.api(self.papi.mfib_signal_dump, {})
|
||||
|
||||
|
Reference in New Issue
Block a user