6a7a358f6cda74c72c15e4c812d779f58d9ba527
[vpp.git] / vpp-api / python / vpp_papi / vpp_papi.py
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
20 import signal, logging, os, sys
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
33 def msg_handler(msg):
34     if not msg:
35         logging.warning('vpp_api.read failed')
36         return
37
38     id = unpack('>H', msg[0:2])
39     logging.debug('Received message', id[0])
40     if id[0] == memclnt.VL_API_RX_THREAD_EXIT:
41         logging.info("We got told to leave")
42         return;
43
44     #
45     # Decode message and returns a tuple.
46     #
47     logging.debug('api_func', api_func_table[id[0]])
48     r = api_func_table[id[0]](msg)
49     if not r:
50         logging.warning('Message decode failed', id[0])
51         return
52
53     if 'context' in r._asdict():
54         if r.context > 0:
55             context = r.context
56
57     #
58     # XXX: Call provided callback for event
59     # Are we guaranteed to not get an event during processing of other messages?
60     # How to differentiate what's a callback message and what not? Context = 0?
61     #
62     if not is_waiting_for_reply():
63         event_callback_call(r)
64         return
65
66     #
67     # Collect results until control ping
68     #
69     if id[0] == vpe.VL_API_CONTROL_PING_REPLY:
70         results_event_set(context)
71         waiting_for_reply_clear()
72         return
73     if not is_results_context(context):
74         logging.warning('Not expecting results for this context', context)
75         return
76     if is_results_more(context):
77         results_append(context, r)
78         return
79
80     results_set(context, r)
81     results_event_set(context)
82     waiting_for_reply_clear()
83
84 def connect(name):
85     signal.alarm(3) # 3 second
86     rv = vpp_api.connect(name, msg_handler)
87     signal.alarm(0)
88     logging.info("Connect:", rv)
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()
99     logging.info("Disconnected")
100     return rv
101
102 def register_event_callback(callback):
103     event_callback_set(callback)
104
105 def plugin_name_to_id(plugin, name_to_id_table, base):
106     try:
107         m = globals()[plugin]
108     except KeyError:
109         m = sys.modules[plugin]
110     for name in name_to_id_table:
111         setattr(m, name, name_to_id_table[name] + base)
112
113 def plugin_map_plugins():
114     for p in plugins:
115         if p == 'memclnt' or p == 'vpe':
116             continue
117
118         #
119         # Find base
120         # Update api table
121         #
122         version = plugins[p]['version']
123         name = p + '_' + format(version, '08x')
124         r = memclnt.get_first_msg_id(name.encode('ascii'))
125
126         ## TODO: Add error handling
127         if r.retval != 0:
128             print('Failed getting first msg id for:', p)
129             continue
130
131         # Set base
132         base = r.first_msg_id
133         msg_id_base_set = plugins[p]['msg_id_base_set']
134         msg_id_base_set(base)
135         plugins[p]['base'] = base
136         func_table = plugins[p]['func_table']
137         i = r.first_msg_id
138         for entry in func_table:
139             api_func_table.insert(i, entry)
140             i += 1
141         plugin_name_to_id(p, plugins[p]['name_to_id_table'], base)
142
143 #
144 # Set up core API
145 #
146 memclnt.msg_id_base_set(1)
147 plugins['memclnt']['base'] = 1
148 msg_id_base_set(len(plugins['memclnt']['func_table']) + 1)
149 plugins['vpe']['base'] = len(plugins['memclnt']['func_table']) + 1
150 api_func_table = []
151 api_func_table.append(None)
152 api_func_table[1:] = plugins['memclnt']['func_table'] + plugins['vpe']['func_table']
153 plugin_name_to_id('memclnt', plugins['memclnt']['name_to_id_table'], 1)
154 plugin_name_to_id('vpe', plugins['vpe']['name_to_id_table'], plugins['vpe']['base'])
155 #logging.basicConfig(level=logging.DEBUG)