| # |
| # 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) |