blob: c5a7eea1e0077352e69ae989744043df18ddb2ba [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
Ole Troan6855f6c2016-04-09 03:16:30 +020016#include <Python.h>
Ole Troan5f9dcff2016-08-01 04:59:13 +020017#include "../pneum/pneum.h"
Dave Barach557d1282016-11-10 14:22:49 -050018#include <vppinfra/hash.h>
Ole Troan6855f6c2016-04-09 03:16:30 +020019
20static PyObject *pneum_callback = NULL;
21
Dave Barach557d1282016-11-10 14:22:49 -050022static void
23wrap_pneum_callback (unsigned char * data, int len)
Ole Troan6855f6c2016-04-09 03:16:30 +020024{
25 PyGILState_STATE gstate;
26 PyObject *result;//, *arglist;
27
28 gstate = PyGILState_Ensure();
29
30 /* Time to call the callback */
Ole Troand06b9f92016-04-25 13:11:19 +020031#if PY_VERSION_HEX >= 0x03000000
Ole Troan6855f6c2016-04-09 03:16:30 +020032 result = PyObject_CallFunction(pneum_callback, "y#", data, len);
Ole Troand06b9f92016-04-25 13:11:19 +020033#else
34 result = PyObject_CallFunction(pneum_callback, "s#", data, len);
35#endif
Ole Troan6855f6c2016-04-09 03:16:30 +020036 if (result)
37 Py_DECREF(result);
38 else
39 PyErr_Print();
40
41 PyGILState_Release(gstate);
Ole Troan6855f6c2016-04-09 03:16:30 +020042}
43
44static PyObject *
Ole Troandfc9b7c2017-03-06 23:51:57 +010045wrap_connect (PyObject *self, PyObject *args, PyObject *kw)
Ole Troan6855f6c2016-04-09 03:16:30 +020046{
Ole Troanb8602b52016-10-05 11:10:50 +020047 char * name, * chroot_prefix = NULL;
Ole Troandfc9b7c2017-03-06 23:51:57 +010048 int rx_qlen = 32; /* default rx queue length */
Ole Troan6855f6c2016-04-09 03:16:30 +020049 int rv;
Dave Barach557d1282016-11-10 14:22:49 -050050 PyObject * temp = NULL;
51 pneum_callback_t cb = NULL;
Ole Troan6855f6c2016-04-09 03:16:30 +020052
Ole Troandfc9b7c2017-03-06 23:51:57 +010053 if (!PyArg_ParseTuple(args, "sOzi:wrap_connect",
54 &name, &temp, &chroot_prefix, &rx_qlen))
Ole Troan6855f6c2016-04-09 03:16:30 +020055 return (NULL);
Ole Troan5f9dcff2016-08-01 04:59:13 +020056
Ole Troandfc9b7c2017-03-06 23:51:57 +010057 if (temp != Py_None)
Dave Barach557d1282016-11-10 14:22:49 -050058 {
59 if (!PyCallable_Check(temp))
60 {
61 PyErr_SetString(PyExc_TypeError, "parameter must be callable");
62 return NULL;
63 }
Ole Troan6855f6c2016-04-09 03:16:30 +020064
Dave Barach557d1282016-11-10 14:22:49 -050065 Py_XINCREF(temp); /* Add a reference to new callback */
66 Py_XDECREF(pneum_callback); /* Dispose of previous callback */
67 pneum_callback = temp; /* Remember new callback */
68 cb = wrap_pneum_callback;
69 }
Ole Troan6855f6c2016-04-09 03:16:30 +020070 Py_BEGIN_ALLOW_THREADS
Dave Barachf9526922017-01-06 16:33:06 -050071 rv = pneum_connect(name, chroot_prefix, cb, rx_qlen);
Ole Troan6855f6c2016-04-09 03:16:30 +020072 Py_END_ALLOW_THREADS
73 return PyLong_FromLong(rv);
74}
75
76static PyObject *
77wrap_disconnect (PyObject *self, PyObject *args)
78{
79 int rv;
80 Py_BEGIN_ALLOW_THREADS
81 rv = pneum_disconnect();
82 Py_END_ALLOW_THREADS
83 return PyLong_FromLong(rv);
84}
Ole Troandfc9b7c2017-03-06 23:51:57 +010085
Ole Troan6855f6c2016-04-09 03:16:30 +020086static PyObject *
87wrap_write (PyObject *self, PyObject *args)
88{
89 char *data;
90 int len, rv;
91
Ole Troan5f9dcff2016-08-01 04:59:13 +020092 if (!PyArg_ParseTuple(args, "s#", &data, &len))
93 return NULL;
Ole Troandfc9b7c2017-03-06 23:51:57 +010094
Ole Troan6855f6c2016-04-09 03:16:30 +020095 Py_BEGIN_ALLOW_THREADS
96 rv = pneum_write(data, len);
97 Py_END_ALLOW_THREADS
98
99 return PyLong_FromLong(rv);
100}
101
Ole Troan6855f6c2016-04-09 03:16:30 +0200102static PyObject *
103wrap_read (PyObject *self, PyObject *args)
104{
105 char *data;
106 int len, rv;
Ole Troandfc9b7c2017-03-06 23:51:57 +0100107 unsigned short timeout;
Ole Troan6855f6c2016-04-09 03:16:30 +0200108
Ole Troandfc9b7c2017-03-06 23:51:57 +0100109 if (!PyArg_ParseTuple(args, "H", &timeout))
110 return (NULL);
Ole Troan6855f6c2016-04-09 03:16:30 +0200111 Py_BEGIN_ALLOW_THREADS
Ole Troandfc9b7c2017-03-06 23:51:57 +0100112 rv = pneum_read(&data, &len, timeout);
Ole Troan6855f6c2016-04-09 03:16:30 +0200113 Py_END_ALLOW_THREADS
114
115 if (rv != 0) { Py_RETURN_NONE; }
Ole Troand06b9f92016-04-25 13:11:19 +0200116#if PY_VERSION_HEX >= 0x03000000
Ole Troan6855f6c2016-04-09 03:16:30 +0200117 PyObject *ret = Py_BuildValue("y#", data, len);
Ole Troand06b9f92016-04-25 13:11:19 +0200118#else
119 PyObject *ret = Py_BuildValue("s#", data, len);
120#endif
Ole Troandfc9b7c2017-03-06 23:51:57 +0100121 pneum_free(data);
Ole Troan6855f6c2016-04-09 03:16:30 +0200122 if (!ret) { Py_RETURN_NONE; }
123
Ole Troan6855f6c2016-04-09 03:16:30 +0200124 return ret;
125}
126
Dave Barach557d1282016-11-10 14:22:49 -0500127static PyObject *
128wrap_msg_table (PyObject *self, PyObject *args)
129{
130 int i = 0, rv = 0;
131 hash_pair_t *hp;
132 uword *h = pneum_msg_table_get_hash();
133 PyObject *ret = PyList_New(pneum_msg_table_size());
134 if (!ret) goto error;
135 hash_foreach_pair (hp, h,
136 ({
137 PyObject *item = PyTuple_New(2);
138 if (!item) goto error;
139 rv = PyTuple_SetItem(item, 0, PyLong_FromLong((u32)hp->value[0]));
140 if (rv) goto error;
141 rv = PyTuple_SetItem(item, 1, PyString_FromString((char *)hp->key));
142 if (rv) goto error;
143 PyList_SetItem(ret, i, item);
144 i++;
145 }));
146
147 return ret;
148
149 error:
150 /* TODO: Raise exception */
151 printf("msg_table failed");
152 Py_RETURN_NONE;
153}
154
Ole Troandfc9b7c2017-03-06 23:51:57 +0100155static PyObject *
156wrap_suspend (PyObject *self, PyObject *args)
157{
158 Py_BEGIN_ALLOW_THREADS
159 pneum_rx_suspend();
160 Py_END_ALLOW_THREADS
161 Py_RETURN_NONE;
162}
163
164static PyObject *
165wrap_resume (PyObject *self, PyObject *args)
166{
167 Py_BEGIN_ALLOW_THREADS
168 pneum_rx_resume();
169 Py_END_ALLOW_THREADS
170 Py_RETURN_NONE;
171}
172
Ole Troan6855f6c2016-04-09 03:16:30 +0200173static PyMethodDef vpp_api_Methods[] = {
174 {"connect", wrap_connect, METH_VARARGS, "Connect to the VPP API."},
175 {"disconnect", wrap_disconnect, METH_VARARGS, "Disconnect from the VPP API."},
176 {"write", wrap_write, METH_VARARGS, "Write data to the VPP API."},
177 {"read", wrap_read, METH_VARARGS, "Read data from the VPP API."},
Dave Barach557d1282016-11-10 14:22:49 -0500178 {"msg_table", wrap_msg_table, METH_VARARGS, "Get API dictionary."},
Ole Troandfc9b7c2017-03-06 23:51:57 +0100179 {"suspend", wrap_suspend, METH_VARARGS, "Suspend RX thread."},
180 {"resume", wrap_resume, METH_VARARGS, "Resume RX thread."},
Ole Troan6855f6c2016-04-09 03:16:30 +0200181 {NULL, NULL, 0, NULL} /* Sentinel */
182};
183
Ole Troand06b9f92016-04-25 13:11:19 +0200184#if PY_VERSION_HEX >= 0x03000000
Ole Troan6855f6c2016-04-09 03:16:30 +0200185PyMODINIT_FUNC
186PyInit_vpp_api (void)
Ole Troand06b9f92016-04-25 13:11:19 +0200187#else
188void
189initvpp_api (void)
190#endif
Ole Troan6855f6c2016-04-09 03:16:30 +0200191{
Ole Troand06b9f92016-04-25 13:11:19 +0200192#if PY_VERSION_HEX >= 0x03000000
193 static struct PyModuleDef vpp_api_module = {
Ole Troan5f9dcff2016-08-01 04:59:13 +0200194#if PY_VERSION_HEX >= 0x03020000
Ole Troand06b9f92016-04-25 13:11:19 +0200195 PyModuleDef_HEAD_INIT,
Ole Troan5f9dcff2016-08-01 04:59:13 +0200196#else
Ole Troand06b9f92016-04-25 13:11:19 +0200197 {
198 PyObject_HEAD_INIT(NULL)
199 NULL, /* m_init */
200 0, /* m_index */
201 NULL, /* m_copy */
202 },
Ole Troan5f9dcff2016-08-01 04:59:13 +0200203#endif
Ole Troand06b9f92016-04-25 13:11:19 +0200204 (char *) "vpp_api",
205 NULL,
206 -1,
207 vpp_api_Methods,
208 NULL,
209 NULL,
210 NULL,
211 NULL
212 };
213#endif
214
Ole Troan6855f6c2016-04-09 03:16:30 +0200215 /* Ensure threading is initialised */
216 if (!PyEval_ThreadsInitialized()) {
217 PyEval_InitThreads();
218 }
Ole Troand06b9f92016-04-25 13:11:19 +0200219
220#if PY_VERSION_HEX >= 0x03000000
Ole Troan6855f6c2016-04-09 03:16:30 +0200221 return PyModule_Create(&vpp_api_module);
Ole Troand06b9f92016-04-25 13:11:19 +0200222#else
223 Py_InitModule((char *) "vpp_api", vpp_api_Methods);
224 return;
225#endif
Ole Troan6855f6c2016-04-09 03:16:30 +0200226}