Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 1 | # |
| 2 | # Copyright (c) 2016 Cisco and/or its affiliates. |
| 3 | # Licensed under the Apache License, Version 2.0 (the "License"); |
| 4 | # you may not use this file except in compliance with the License. |
| 5 | # You may obtain a copy of the License at: |
| 6 | # |
| 7 | # http://www.apache.org/licenses/LICENSE-2.0 |
| 8 | # |
| 9 | # Unless required by applicable law or agreed to in writing, software |
| 10 | # distributed under the License is distributed on an "AS IS" BASIS, |
| 11 | # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
| 12 | # See the License for the specific language governing permissions and |
| 13 | # limitations under the License. |
| 14 | |
| 15 | # |
| 16 | # Import C API shared object |
| 17 | # |
| 18 | from __future__ import print_function |
| 19 | |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame^] | 20 | import signal, os, sys |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 21 | from struct import * |
| 22 | |
| 23 | scriptdir = os.path.dirname(os.path.realpath(__file__)) |
| 24 | sys.path.append(scriptdir) |
| 25 | import vpp_api |
| 26 | from vpp_api_base import * |
| 27 | |
| 28 | # Import API definitions. The core VPE API is imported into main namespace |
| 29 | import memclnt |
| 30 | from vpe import * |
| 31 | vpe = sys.modules['vpe'] |
| 32 | |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame^] | 33 | def eprint(*args, **kwargs): |
| 34 | print(*args, file=sys.stderr, **kwargs) |
| 35 | |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 36 | def msg_handler(msg): |
| 37 | if not msg: |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame^] | 38 | eprint('vpp_api.read failed') |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 39 | return |
| 40 | |
| 41 | id = unpack('>H', msg[0:2]) |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 42 | if id[0] == memclnt.VL_API_RX_THREAD_EXIT: |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 43 | return; |
| 44 | |
| 45 | # |
| 46 | # Decode message and returns a tuple. |
| 47 | # |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame^] | 48 | try: |
| 49 | r = api_func_table[id[0]](msg) |
| 50 | except: |
| 51 | eprint('Message decode failed', id[0], api_func_table[id[0]]) |
| 52 | raise |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 53 | |
| 54 | if 'context' in r._asdict(): |
| 55 | if r.context > 0: |
| 56 | context = r.context |
| 57 | |
| 58 | # |
| 59 | # XXX: Call provided callback for event |
| 60 | # Are we guaranteed to not get an event during processing of other messages? |
| 61 | # How to differentiate what's a callback message and what not? Context = 0? |
| 62 | # |
| 63 | if not is_waiting_for_reply(): |
| 64 | event_callback_call(r) |
| 65 | return |
| 66 | |
| 67 | # |
| 68 | # Collect results until control ping |
| 69 | # |
| 70 | if id[0] == vpe.VL_API_CONTROL_PING_REPLY: |
| 71 | results_event_set(context) |
| 72 | waiting_for_reply_clear() |
| 73 | return |
| 74 | if not is_results_context(context): |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame^] | 75 | eprint('Not expecting results for this context', context) |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 76 | return |
| 77 | if is_results_more(context): |
| 78 | results_append(context, r) |
| 79 | return |
| 80 | |
| 81 | results_set(context, r) |
| 82 | results_event_set(context) |
| 83 | waiting_for_reply_clear() |
| 84 | |
| 85 | def connect(name): |
| 86 | signal.alarm(3) # 3 second |
| 87 | rv = vpp_api.connect(name, msg_handler) |
| 88 | signal.alarm(0) |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 89 | |
| 90 | # |
| 91 | # Assign message id space for plugins |
| 92 | # |
| 93 | plugin_map_plugins() |
| 94 | |
| 95 | return rv |
| 96 | |
| 97 | def disconnect(): |
| 98 | rv = vpp_api.disconnect() |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 99 | return rv |
| 100 | |
Ole Troan | c27213a | 2016-08-31 14:50:49 +0200 | [diff] [blame] | 101 | # CLI convenience wrapper |
| 102 | def cli_exec(cmd): |
| 103 | cmd += '\n' |
| 104 | r = cli_inband(len(cmd), cmd) |
| 105 | return r.reply[0].decode().rstrip('\x00') |
| 106 | |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 107 | def register_event_callback(callback): |
| 108 | event_callback_set(callback) |
| 109 | |
| 110 | def plugin_name_to_id(plugin, name_to_id_table, base): |
| 111 | try: |
| 112 | m = globals()[plugin] |
| 113 | except KeyError: |
| 114 | m = sys.modules[plugin] |
| 115 | for name in name_to_id_table: |
| 116 | setattr(m, name, name_to_id_table[name] + base) |
| 117 | |
| 118 | def plugin_map_plugins(): |
| 119 | for p in plugins: |
| 120 | if p == 'memclnt' or p == 'vpe': |
| 121 | continue |
| 122 | |
| 123 | # |
| 124 | # Find base |
| 125 | # Update api table |
| 126 | # |
| 127 | version = plugins[p]['version'] |
| 128 | name = p + '_' + format(version, '08x') |
| 129 | r = memclnt.get_first_msg_id(name.encode('ascii')) |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame^] | 130 | ## TODO: Add error handling / raise exception |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 131 | if r.retval != 0: |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame^] | 132 | eprint('Failed getting first msg id for:', p) |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 133 | continue |
| 134 | |
| 135 | # Set base |
| 136 | base = r.first_msg_id |
| 137 | msg_id_base_set = plugins[p]['msg_id_base_set'] |
| 138 | msg_id_base_set(base) |
| 139 | plugins[p]['base'] = base |
| 140 | func_table = plugins[p]['func_table'] |
| 141 | i = r.first_msg_id |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame^] | 142 | # Insert doesn't extend the table |
| 143 | if i + len(func_table) > len(api_func_table): |
| 144 | fill = [None] * (i + len(func_table) - len(api_func_table)) |
| 145 | api_func_table.extend(fill) |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 146 | for entry in func_table: |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame^] | 147 | api_func_table[i] = entry |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 148 | i += 1 |
| 149 | plugin_name_to_id(p, plugins[p]['name_to_id_table'], base) |
| 150 | |
| 151 | # |
| 152 | # Set up core API |
| 153 | # |
| 154 | memclnt.msg_id_base_set(1) |
| 155 | plugins['memclnt']['base'] = 1 |
| 156 | msg_id_base_set(len(plugins['memclnt']['func_table']) + 1) |
| 157 | plugins['vpe']['base'] = len(plugins['memclnt']['func_table']) + 1 |
| 158 | api_func_table = [] |
| 159 | api_func_table.append(None) |
| 160 | api_func_table[1:] = plugins['memclnt']['func_table'] + plugins['vpe']['func_table'] |
| 161 | plugin_name_to_id('memclnt', plugins['memclnt']['name_to_id_table'], 1) |
| 162 | plugin_name_to_id('vpe', plugins['vpe']['name_to_id_table'], plugins['vpe']['base']) |