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 | |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 23 | import vpp_api |
| 24 | from vpp_api_base import * |
| 25 | |
| 26 | # Import API definitions. The core VPE API is imported into main namespace |
| 27 | import memclnt |
Ole Troan | 57c3d66 | 2016-09-12 22:00:32 +0200 | [diff] [blame] | 28 | |
| 29 | # Cheating a bit, importing it into this namespace as well as a module. |
| 30 | import vpe |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 31 | from vpe import * |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 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 | # |
Ole Troan | 57c3d66 | 2016-09-12 22:00:32 +0200 | [diff] [blame] | 70 | if id[0] == VL_API_CONTROL_PING_REPLY: |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 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 | |
Ole Troan | 57c3d66 | 2016-09-12 22:00:32 +0200 | [diff] [blame] | 85 | def handler(signum, frame): |
| 86 | print('Signal handler called with signal', signum) |
| 87 | raise IOError("Couldn't connect to VPP!") |
| 88 | |
Ole Troan | b8602b5 | 2016-10-05 11:10:50 +0200 | [diff] [blame] | 89 | def connect(name, chroot_prefix = None): |
Ole Troan | 57c3d66 | 2016-09-12 22:00:32 +0200 | [diff] [blame] | 90 | # Set the signal handler |
| 91 | signal.signal(signal.SIGALRM, handler) |
| 92 | |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 93 | signal.alarm(3) # 3 second |
Ole Troan | b8602b5 | 2016-10-05 11:10:50 +0200 | [diff] [blame] | 94 | if not chroot_prefix: |
| 95 | rv = vpp_api.connect(name, msg_handler) |
| 96 | else: |
| 97 | rv = vpp_api.connect(name, msg_handler, chroot_prefix) |
| 98 | |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 99 | signal.alarm(0) |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 100 | |
| 101 | # |
| 102 | # Assign message id space for plugins |
| 103 | # |
Ole Troan | 57c3d66 | 2016-09-12 22:00:32 +0200 | [diff] [blame] | 104 | try: |
| 105 | plugin_map_plugins() |
| 106 | except: |
| 107 | return -1 |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 108 | return rv |
| 109 | |
| 110 | def disconnect(): |
| 111 | rv = vpp_api.disconnect() |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 112 | return rv |
| 113 | |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 114 | def register_event_callback(callback): |
| 115 | event_callback_set(callback) |
| 116 | |
| 117 | def plugin_name_to_id(plugin, name_to_id_table, base): |
| 118 | try: |
| 119 | m = globals()[plugin] |
| 120 | except KeyError: |
| 121 | m = sys.modules[plugin] |
Ole Troan | 57c3d66 | 2016-09-12 22:00:32 +0200 | [diff] [blame] | 122 | |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 123 | for name in name_to_id_table: |
| 124 | setattr(m, name, name_to_id_table[name] + base) |
| 125 | |
| 126 | def plugin_map_plugins(): |
| 127 | for p in plugins: |
| 128 | if p == 'memclnt' or p == 'vpe': |
| 129 | continue |
| 130 | |
| 131 | # |
| 132 | # Find base |
| 133 | # Update api table |
| 134 | # |
| 135 | version = plugins[p]['version'] |
| 136 | name = p + '_' + format(version, '08x') |
Ole Troan | 57c3d66 | 2016-09-12 22:00:32 +0200 | [diff] [blame] | 137 | r = memclnt.get_first_msg_id(name) |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 138 | if r.retval != 0: |
Ole Troan | 57c3d66 | 2016-09-12 22:00:32 +0200 | [diff] [blame] | 139 | eprint('Failed getting first msg id for:', p, r, name) |
| 140 | raise |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 141 | |
| 142 | # Set base |
| 143 | base = r.first_msg_id |
| 144 | msg_id_base_set = plugins[p]['msg_id_base_set'] |
| 145 | msg_id_base_set(base) |
| 146 | plugins[p]['base'] = base |
| 147 | func_table = plugins[p]['func_table'] |
| 148 | i = r.first_msg_id |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame] | 149 | # Insert doesn't extend the table |
| 150 | if i + len(func_table) > len(api_func_table): |
| 151 | fill = [None] * (i + len(func_table) - len(api_func_table)) |
| 152 | api_func_table.extend(fill) |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 153 | for entry in func_table: |
Ole Troan | 1732fc1 | 2016-08-30 21:03:51 +0200 | [diff] [blame] | 154 | api_func_table[i] = entry |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 155 | i += 1 |
| 156 | plugin_name_to_id(p, plugins[p]['name_to_id_table'], base) |
| 157 | |
| 158 | # |
| 159 | # Set up core API |
| 160 | # |
| 161 | memclnt.msg_id_base_set(1) |
| 162 | plugins['memclnt']['base'] = 1 |
Ole Troan | 57c3d66 | 2016-09-12 22:00:32 +0200 | [diff] [blame] | 163 | |
| 164 | # vpe |
Ole Troan | 5f9dcff | 2016-08-01 04:59:13 +0200 | [diff] [blame] | 165 | msg_id_base_set(len(plugins['memclnt']['func_table']) + 1) |
| 166 | plugins['vpe']['base'] = len(plugins['memclnt']['func_table']) + 1 |
| 167 | api_func_table = [] |
| 168 | api_func_table.append(None) |
| 169 | api_func_table[1:] = plugins['memclnt']['func_table'] + plugins['vpe']['func_table'] |
| 170 | plugin_name_to_id('memclnt', plugins['memclnt']['name_to_id_table'], 1) |
| 171 | plugin_name_to_id('vpe', plugins['vpe']['name_to_id_table'], plugins['vpe']['base']) |
Ole Troan | 57c3d66 | 2016-09-12 22:00:32 +0200 | [diff] [blame] | 172 | plugin_name_to_id(__name__, plugins['vpe']['name_to_id_table'], plugins['vpe']['base']) |