blob: 174e61d7e9e0ff7141fd6f656cdb89214d20b306 [file] [log] [blame]
Ole Troan5f9dcff2016-08-01 04:59:13 +02001#
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#
18from __future__ import print_function
19
Ole Troan1732fc12016-08-30 21:03:51 +020020import signal, os, sys
Ole Troan5f9dcff2016-08-01 04:59:13 +020021from struct import *
22
23scriptdir = os.path.dirname(os.path.realpath(__file__))
24sys.path.append(scriptdir)
25import vpp_api
26from vpp_api_base import *
27
28# Import API definitions. The core VPE API is imported into main namespace
29import memclnt
30from vpe import *
31vpe = sys.modules['vpe']
32
Ole Troan1732fc12016-08-30 21:03:51 +020033def eprint(*args, **kwargs):
34 print(*args, file=sys.stderr, **kwargs)
35
Ole Troan5f9dcff2016-08-01 04:59:13 +020036def msg_handler(msg):
37 if not msg:
Ole Troan1732fc12016-08-30 21:03:51 +020038 eprint('vpp_api.read failed')
Ole Troan5f9dcff2016-08-01 04:59:13 +020039 return
40
41 id = unpack('>H', msg[0:2])
Ole Troan5f9dcff2016-08-01 04:59:13 +020042 if id[0] == memclnt.VL_API_RX_THREAD_EXIT:
Ole Troan5f9dcff2016-08-01 04:59:13 +020043 return;
44
45 #
46 # Decode message and returns a tuple.
47 #
Ole Troan1732fc12016-08-30 21:03:51 +020048 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 Troan5f9dcff2016-08-01 04:59:13 +020053
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 Troan1732fc12016-08-30 21:03:51 +020075 eprint('Not expecting results for this context', context)
Ole Troan5f9dcff2016-08-01 04:59:13 +020076 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
85def connect(name):
86 signal.alarm(3) # 3 second
87 rv = vpp_api.connect(name, msg_handler)
88 signal.alarm(0)
Ole Troan5f9dcff2016-08-01 04:59:13 +020089
90 #
91 # Assign message id space for plugins
92 #
93 plugin_map_plugins()
94
95 return rv
96
97def disconnect():
98 rv = vpp_api.disconnect()
Ole Troan5f9dcff2016-08-01 04:59:13 +020099 return rv
100
Ole Troanc27213a2016-08-31 14:50:49 +0200101# CLI convenience wrapper
102def cli_exec(cmd):
103 cmd += '\n'
104 r = cli_inband(len(cmd), cmd)
105 return r.reply[0].decode().rstrip('\x00')
106
Ole Troan5f9dcff2016-08-01 04:59:13 +0200107def register_event_callback(callback):
108 event_callback_set(callback)
109
110def 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
118def 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 Troan1732fc12016-08-30 21:03:51 +0200130 ## TODO: Add error handling / raise exception
Ole Troan5f9dcff2016-08-01 04:59:13 +0200131 if r.retval != 0:
Ole Troan1732fc12016-08-30 21:03:51 +0200132 eprint('Failed getting first msg id for:', p)
Ole Troan5f9dcff2016-08-01 04:59:13 +0200133 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 Troan1732fc12016-08-30 21:03:51 +0200142 # 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 Troan5f9dcff2016-08-01 04:59:13 +0200146 for entry in func_table:
Ole Troan1732fc12016-08-30 21:03:51 +0200147 api_func_table[i] = entry
Ole Troan5f9dcff2016-08-01 04:59:13 +0200148 i += 1
149 plugin_name_to_id(p, plugins[p]['name_to_id_table'], base)
150
151#
152# Set up core API
153#
154memclnt.msg_id_base_set(1)
155plugins['memclnt']['base'] = 1
156msg_id_base_set(len(plugins['memclnt']['func_table']) + 1)
157plugins['vpe']['base'] = len(plugins['memclnt']['func_table']) + 1
158api_func_table = []
159api_func_table.append(None)
160api_func_table[1:] = plugins['memclnt']['func_table'] + plugins['vpe']['func_table']
161plugin_name_to_id('memclnt', plugins['memclnt']['name_to_id_table'], 1)
162plugin_name_to_id('vpe', plugins['vpe']['name_to_id_table'], plugins['vpe']['base'])