diff options
author | Ole Troan <ot@cisco.com> | 2016-08-01 04:59:13 +0200 |
---|---|---|
committer | Damjan Marion <dmarion.lists@gmail.com> | 2016-08-25 00:29:40 +0000 |
commit | 5f9dcff39d5e25c6bef30d569e405635633f3c69 (patch) | |
tree | ec14d5fdb45a9d82cf5703d63e0bcafcc40d4da0 /vpp-api/python/vpp_papi/vpp_papi.py | |
parent | 151fb725636f192da8a04d0f74dc3455b58dd61c (diff) |
VPP Python language binding - plugin support
- Moved Python generator tool to tools directory
- Added build-vpp-api Makefile target
- Generator now only creates a Python representation of the .api
the rest of the framework is in the vpp_papi script
- Each plugin has its own namespace.
- Plugin Python files are installed in vpp_papi_plugins for easy
use inside the build tree.
Change-Id: I272c83bb7e5d5e416bdbd8a790a3cc35c5a04e38
Signed-off-by: Ole Troan <ot@cisco.com>
Diffstat (limited to 'vpp-api/python/vpp_papi/vpp_papi.py')
-rw-r--r-- | vpp-api/python/vpp_papi/vpp_papi.py | 155 |
1 files changed, 155 insertions, 0 deletions
diff --git a/vpp-api/python/vpp_papi/vpp_papi.py b/vpp-api/python/vpp_papi/vpp_papi.py new file mode 100644 index 00000000000..6a7a358f6cd --- /dev/null +++ b/vpp-api/python/vpp_papi/vpp_papi.py @@ -0,0 +1,155 @@ +# +# Copyright (c) 2016 Cisco and/or its affiliates. +# 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. + +# +# Import C API shared object +# +from __future__ import print_function + +import signal, logging, os, sys +from struct import * + +scriptdir = os.path.dirname(os.path.realpath(__file__)) +sys.path.append(scriptdir) +import vpp_api +from vpp_api_base import * + +# Import API definitions. The core VPE API is imported into main namespace +import memclnt +from vpe import * +vpe = sys.modules['vpe'] + +def msg_handler(msg): + if not msg: + logging.warning('vpp_api.read failed') + return + + id = unpack('>H', msg[0:2]) + logging.debug('Received message', id[0]) + if id[0] == memclnt.VL_API_RX_THREAD_EXIT: + logging.info("We got told to leave") + return; + + # + # Decode message and returns a tuple. + # + logging.debug('api_func', api_func_table[id[0]]) + r = api_func_table[id[0]](msg) + if not r: + logging.warning('Message decode failed', id[0]) + return + + if 'context' in r._asdict(): + if r.context > 0: + context = r.context + + # + # XXX: Call provided callback for event + # Are we guaranteed to not get an event during processing of other messages? + # How to differentiate what's a callback message and what not? Context = 0? + # + if not is_waiting_for_reply(): + event_callback_call(r) + return + + # + # Collect results until control ping + # + if id[0] == vpe.VL_API_CONTROL_PING_REPLY: + results_event_set(context) + waiting_for_reply_clear() + return + if not is_results_context(context): + logging.warning('Not expecting results for this context', context) + return + if is_results_more(context): + results_append(context, r) + return + + results_set(context, r) + results_event_set(context) + waiting_for_reply_clear() + +def connect(name): + signal.alarm(3) # 3 second + rv = vpp_api.connect(name, msg_handler) + signal.alarm(0) + logging.info("Connect:", rv) + + # + # Assign message id space for plugins + # + plugin_map_plugins() + + return rv + +def disconnect(): + rv = vpp_api.disconnect() + logging.info("Disconnected") + return rv + +def register_event_callback(callback): + event_callback_set(callback) + +def plugin_name_to_id(plugin, name_to_id_table, base): + try: + m = globals()[plugin] + except KeyError: + m = sys.modules[plugin] + for name in name_to_id_table: + setattr(m, name, name_to_id_table[name] + base) + +def plugin_map_plugins(): + for p in plugins: + if p == 'memclnt' or p == 'vpe': + continue + + # + # Find base + # Update api table + # + version = plugins[p]['version'] + name = p + '_' + format(version, '08x') + r = memclnt.get_first_msg_id(name.encode('ascii')) + + ## TODO: Add error handling + if r.retval != 0: + print('Failed getting first msg id for:', p) + continue + + # Set base + base = r.first_msg_id + msg_id_base_set = plugins[p]['msg_id_base_set'] + msg_id_base_set(base) + plugins[p]['base'] = base + func_table = plugins[p]['func_table'] + i = r.first_msg_id + for entry in func_table: + api_func_table.insert(i, entry) + i += 1 + plugin_name_to_id(p, plugins[p]['name_to_id_table'], base) + +# +# Set up core API +# +memclnt.msg_id_base_set(1) +plugins['memclnt']['base'] = 1 +msg_id_base_set(len(plugins['memclnt']['func_table']) + 1) +plugins['vpe']['base'] = len(plugins['memclnt']['func_table']) + 1 +api_func_table = [] +api_func_table.append(None) +api_func_table[1:] = plugins['memclnt']['func_table'] + plugins['vpe']['func_table'] +plugin_name_to_id('memclnt', plugins['memclnt']['name_to_id_table'], 1) +plugin_name_to_id('vpe', plugins['vpe']['name_to_id_table'], plugins['vpe']['base']) +#logging.basicConfig(level=logging.DEBUG) |