X-Git-Url: https://gerrit.fd.io/r/gitweb?a=blobdiff_plain;f=src%2Fvpp-api%2Fpython%2Fvpp_papi%2Fvpp_papi.py;h=78809653ddb5e6ca6c2380f688acbcd53231de52;hb=refs%2Fchanges%2F61%2F20161%2F3;hp=4de257c6924a48953faced4d701e0af55949d67c;hpb=413f4a5b2123c1625d615315db293a080078482b;p=vpp.git diff --git a/src/vpp-api/python/vpp_papi/vpp_papi.py b/src/vpp-api/python/vpp_papi/vpp_papi.py index 4de257c6924..78809653ddb 100644 --- a/src/vpp-api/python/vpp_papi/vpp_papi.py +++ b/src/vpp-api/python/vpp_papi/vpp_papi.py @@ -16,11 +16,14 @@ from __future__ import print_function from __future__ import absolute_import +import ctypes import sys +import multiprocessing as mp import os import logging import collections import struct +import functools import json import threading import fnmatch @@ -28,6 +31,7 @@ import weakref import atexit from . vpp_serializer import VPPType, VPPEnumType, VPPUnionType, BaseTypes from . vpp_serializer import VPPMessage, vpp_get_type, VPPTypeAlias +from . macaddress import MACAddress, mac_pton, mac_ntop logger = logging.getLogger(__name__) @@ -37,17 +41,23 @@ else: import queue as queue +def metaclass(metaclass): + @functools.wraps(metaclass) + def wrapper(cls): + return metaclass(cls.__name__, cls.__bases__, cls.__dict__.copy()) + + return wrapper + + class VppEnumType(type): def __getattr__(cls, name): t = vpp_get_type(name) return t.enum -# Python3 -# class VppEnum(metaclass=VppEnumType): -# pass +@metaclass(VppEnumType) class VppEnum(object): - __metaclass__ = VppEnumType + pass def vpp_atexit(vpp_weakref): @@ -57,6 +67,7 @@ def vpp_atexit(vpp_weakref): vpp_instance.logger.debug('Cleaning up VPP on exit') vpp_instance.disconnect() + if sys.version[0] == '2': def vpp_iterator(d): return d.iteritems() @@ -86,6 +97,7 @@ class FuncWrapper(object): def __init__(self, func): self._func = func self.__name__ = func.__name__ + self.__doc__ = func.__doc__ def __call__(self, **kwargs): return self._func(**kwargs) @@ -111,7 +123,7 @@ class VPPValueError(ValueError): pass -class VPP(object): +class VPPApiClient(object): """VPP interface. This class provides the APIs to VPP. The APIs are loaded @@ -123,6 +135,7 @@ class VPP(object): provides a means to register a callback function to receive these messages in a background thread. """ + apidir = None VPPApiError = VPPApiError VPPRuntimeError = VPPRuntimeError VPPValueError = VPPValueError @@ -218,6 +231,11 @@ class VPP(object): self.message_queue = queue.Queue() self.read_timeout = read_timeout self.async_thread = async_thread + self.event_thread = None + self.testmode = testmode + self.use_socket = use_socket + self.server_address = server_address + self._apifiles = apifiles if use_socket: from . vpp_transport_socket import VppTransport @@ -251,16 +269,16 @@ class VPP(object): atexit.register(vpp_atexit, weakref.ref(self)) class ContextId(object): - """Thread-safe provider of unique context IDs.""" + """Multiprocessing-safe provider of unique context IDs.""" def __init__(self): - self.context = 0 - self.lock = threading.Lock() + self.context = mp.Value(ctypes.c_uint, 0) + self.lock = mp.Lock() def __call__(self): """Get a new unique (or, at least, not recently used) context.""" with self.lock: - self.context += 1 - return self.context + self.context.value += 1 + return self.context.value get_context = ContextId() def get_type(self, name): @@ -278,10 +296,7 @@ class VPP(object): :returns: A single directory name, or None if no such directory could be found. """ - dirs = [] - - if 'VPP_API_DIR' in os.environ: - dirs.append(os.environ['VPP_API_DIR']) + dirs = [cls.apidir] if cls.apidir else [] # perhaps we're in the 'src/scripts' or 'src/vpp-api/python' dir; # in which case, plot a course to likely places in the src tree @@ -343,7 +358,7 @@ class VPP(object): # finally, try the location system packages typically install into dirs.append(os.path.sep.join(('', 'usr', 'share', 'vpp', 'api'))) - # check the directories for existance; first one wins + # check the directories for existence; first one wins for dir in dirs: if os.path.isdir(dir): return dir @@ -408,6 +423,8 @@ class VPP(object): f.__doc__ = ", ".join(["%s %s" % (msg.fieldtypes[j], k) for j, k in enumerate(msg.fields)]) + f.msg = msg + return f def _register_functions(self, do_async=False): @@ -416,7 +433,7 @@ class VPP(object): self._api = VppApiDynamicMethodHolder() for name, msg in vpp_iterator(self.messages): n = name + '_' + msg.crc[2:] - i = self.transport.get_msg_index(n.encode()) + i = self.transport.get_msg_index(n.encode('utf-8')) if i > 0: self.id_msgdef[i] = msg self.id_names[i] = name @@ -436,9 +453,10 @@ class VPP(object): def connect_internal(self, name, msg_handler, chroot_prefix, rx_qlen, do_async): - pfx = chroot_prefix.encode() if chroot_prefix else None + pfx = chroot_prefix.encode('utf-8') if chroot_prefix else None - rv = self.transport.connect(name.encode(), pfx, msg_handler, rx_qlen) + rv = self.transport.connect(name.encode('utf-8'), pfx, + msg_handler, rx_qlen) if rv != 0: raise VPPIOError(2, 'Connect failed') self.vpp_dictionary_maxid = self.transport.msg_table_max_index() @@ -447,13 +465,15 @@ class VPP(object): # Initialise control ping crc = self.messages['control_ping'].crc self.control_ping_index = self.transport.get_msg_index( - ('control_ping' + '_' + crc[2:]).encode()) + ('control_ping' + '_' + crc[2:]).encode('utf-8')) self.control_ping_msgdef = self.messages['control_ping'] if self.async_thread: self.event_thread = threading.Thread( target=self.thread_msg_handler) self.event_thread.daemon = True self.event_thread.start() + else: + self.event_thread = None return rv def connect(self, name, chroot_prefix=None, do_async=False, rx_qlen=32): @@ -484,7 +504,8 @@ class VPP(object): def disconnect(self): """Detach from VPP.""" rv = self.transport.disconnect() - self.message_queue.put("terminate event thread") + if self.event_thread is not None: + self.message_queue.put("terminate event thread") return rv def msg_handler_sync(self, msg): @@ -700,5 +721,16 @@ class VPP(object): if self.event_callback: self.event_callback(msgname, r) + def __repr__(self): + return "" % ( + self._apifiles, self.testmode, self.async_thread, + self.logger, self.read_timeout, self.use_socket, + self.server_address) + + +# Provide the old name for backward compatibility. +VPP = VPPApiClient # vim: tabstop=8 expandtab shiftwidth=4 softtabstop=4