1fa1456a3SAndrew Yourtchenko--[[
2fa1456a3SAndrew Yourtchenko/*
3fa1456a3SAndrew Yourtchenko * Copyright (c) 2016 Cisco and/or its affiliates.
4fa1456a3SAndrew Yourtchenko * Licensed under the Apache License, Version 2.0 (the "License");
5fa1456a3SAndrew Yourtchenko * you may not use this file except in compliance with the License.
6fa1456a3SAndrew Yourtchenko * You may obtain a copy of the License at:
7fa1456a3SAndrew Yourtchenko *
8fa1456a3SAndrew Yourtchenko *     http://www.apache.org/licenses/LICENSE-2.0
9fa1456a3SAndrew Yourtchenko *
10fa1456a3SAndrew Yourtchenko * Unless required by applicable law or agreed to in writing, software
11fa1456a3SAndrew Yourtchenko * distributed under the License is distributed on an "AS IS" BASIS,
12fa1456a3SAndrew Yourtchenko * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13fa1456a3SAndrew Yourtchenko * See the License for the specific language governing permissions and
14fa1456a3SAndrew Yourtchenko * limitations under the License.
15fa1456a3SAndrew Yourtchenko */
16fa1456a3SAndrew Yourtchenko]]
17fa1456a3SAndrew Yourtchenko
18b868e4eaSAndrew Yourtchenko-- json decode/encode from https://gist.github.com/tylerneylon/59f4bcf316be525b30ab
19b868e4eaSAndrew Yourtchenko-- licensed by the author tylerneylon into public domain. Thanks!
20b868e4eaSAndrew Yourtchenko
21b868e4eaSAndrew Yourtchenkolocal json = {}
22b868e4eaSAndrew Yourtchenko
23b868e4eaSAndrew Yourtchenko-- Internal functions.
24b868e4eaSAndrew Yourtchenko
25b868e4eaSAndrew Yourtchenkolocal function kind_of(obj)
26b868e4eaSAndrew Yourtchenko  if type(obj) ~= 'table' then return type(obj) end
27b868e4eaSAndrew Yourtchenko  local i = 1
28b868e4eaSAndrew Yourtchenko  for _ in pairs(obj) do
29b868e4eaSAndrew Yourtchenko    if obj[i] ~= nil then i = i + 1 else return 'table' end
30b868e4eaSAndrew Yourtchenko  end
31b868e4eaSAndrew Yourtchenko  if i == 1 then return 'table' else return 'array' end
32b868e4eaSAndrew Yourtchenkoend
33b868e4eaSAndrew Yourtchenko
34b868e4eaSAndrew Yourtchenkolocal function escape_str(s)
35b868e4eaSAndrew Yourtchenko  local in_char  = {'\\', '"', '/', '\b', '\f', '\n', '\r', '\t'}
36b868e4eaSAndrew Yourtchenko  local out_char = {'\\', '"', '/',  'b',  'f',  'n',  'r',  't'}
37b868e4eaSAndrew Yourtchenko  for i, c in ipairs(in_char) do
38b868e4eaSAndrew Yourtchenko    s = s:gsub(c, '\\' .. out_char[i])
39b868e4eaSAndrew Yourtchenko  end
40b868e4eaSAndrew Yourtchenko  return s
41b868e4eaSAndrew Yourtchenkoend
42b868e4eaSAndrew Yourtchenko
43b868e4eaSAndrew Yourtchenko-- Returns pos, did_find; there are two cases:
44b868e4eaSAndrew Yourtchenko-- 1. Delimiter found: pos = pos after leading space + delim; did_find = true.
45b868e4eaSAndrew Yourtchenko-- 2. Delimiter not found: pos = pos after leading space;     did_find = false.
46b868e4eaSAndrew Yourtchenko-- This throws an error if err_if_missing is true and the delim is not found.
47b868e4eaSAndrew Yourtchenkolocal function skip_delim(str, pos, delim, err_if_missing)
48b868e4eaSAndrew Yourtchenko  pos = pos + #str:match('^%s*', pos)
49b868e4eaSAndrew Yourtchenko  if str:sub(pos, pos) ~= delim then
50b868e4eaSAndrew Yourtchenko    if err_if_missing then
51b868e4eaSAndrew Yourtchenko      error('Expected ' .. delim .. ' near position ' .. pos)
52b868e4eaSAndrew Yourtchenko    end
53b868e4eaSAndrew Yourtchenko    return pos, false
54b868e4eaSAndrew Yourtchenko  end
55b868e4eaSAndrew Yourtchenko  return pos + 1, true
56b868e4eaSAndrew Yourtchenkoend
57b868e4eaSAndrew Yourtchenko
58b868e4eaSAndrew Yourtchenko-- Expects the given pos to be the first character after the opening quote.
59b868e4eaSAndrew Yourtchenko-- Returns val, pos; the returned pos is after the closing quote character.
60b868e4eaSAndrew Yourtchenkolocal function parse_str_val(str, pos, val)
61b868e4eaSAndrew Yourtchenko  val = val or ''
62b868e4eaSAndrew Yourtchenko  local early_end_error = 'End of input found while parsing string.'
63b868e4eaSAndrew Yourtchenko  if pos > #str then error(early_end_error) end
64b868e4eaSAndrew Yourtchenko  local c = str:sub(pos, pos)
65b868e4eaSAndrew Yourtchenko  if c == '"'  then return val, pos + 1 end
66b868e4eaSAndrew Yourtchenko  if c ~= '\\' then return parse_str_val(str, pos + 1, val .. c) end
67b868e4eaSAndrew Yourtchenko  -- We must have a \ character.
68b868e4eaSAndrew Yourtchenko  local esc_map = {b = '\b', f = '\f', n = '\n', r = '\r', t = '\t'}
69b868e4eaSAndrew Yourtchenko  local nextc = str:sub(pos + 1, pos + 1)
70b868e4eaSAndrew Yourtchenko  if not nextc then error(early_end_error) end
71b868e4eaSAndrew Yourtchenko  return parse_str_val(str, pos + 2, val .. (esc_map[nextc] or nextc))
72b868e4eaSAndrew Yourtchenkoend
73b868e4eaSAndrew Yourtchenko
74b868e4eaSAndrew Yourtchenko-- Returns val, pos; the returned pos is after the number's final character.
75b868e4eaSAndrew Yourtchenkolocal function parse_num_val(str, pos)
76b868e4eaSAndrew Yourtchenko  local num_str = str:match('^-?%d+%.?%d*[eE]?[+-]?%d*', pos)
77b868e4eaSAndrew Yourtchenko  local val = tonumber(num_str)
78b868e4eaSAndrew Yourtchenko  if not val then error('Error parsing number at position ' .. pos .. '.') end
79b868e4eaSAndrew Yourtchenko  return val, pos + #num_str
80b868e4eaSAndrew Yourtchenkoend
81b868e4eaSAndrew Yourtchenko
82b868e4eaSAndrew Yourtchenko
83b868e4eaSAndrew Yourtchenko-- Public values and functions.
84b868e4eaSAndrew Yourtchenko
85b868e4eaSAndrew Yourtchenkofunction json.stringify(obj, as_key)
86b868e4eaSAndrew Yourtchenko  local s = {}  -- We'll build the string as an array of strings to be concatenated.
87b868e4eaSAndrew Yourtchenko  local kind = kind_of(obj)  -- This is 'array' if it's an array or type(obj) otherwise.
88b868e4eaSAndrew Yourtchenko  if kind == 'array' then
89b868e4eaSAndrew Yourtchenko    if as_key then error('Can\'t encode array as key.') end
90b868e4eaSAndrew Yourtchenko    s[#s + 1] = '['
91b868e4eaSAndrew Yourtchenko    for i, val in ipairs(obj) do
92b868e4eaSAndrew Yourtchenko      if i > 1 then s[#s + 1] = ', ' end
93b868e4eaSAndrew Yourtchenko      s[#s + 1] = json.stringify(val)
94b868e4eaSAndrew Yourtchenko    end
95b868e4eaSAndrew Yourtchenko    s[#s + 1] = ']'
96b868e4eaSAndrew Yourtchenko  elseif kind == 'table' then
97b868e4eaSAndrew Yourtchenko    if as_key then error('Can\'t encode table as key.') end
98b868e4eaSAndrew Yourtchenko    s[#s + 1] = '{'
99b868e4eaSAndrew Yourtchenko    for k, v in pairs(obj) do
100b868e4eaSAndrew Yourtchenko      if #s > 1 then s[#s + 1] = ', ' end
101b868e4eaSAndrew Yourtchenko      s[#s + 1] = json.stringify(k, true)
102b868e4eaSAndrew Yourtchenko      s[#s + 1] = ':'
103b868e4eaSAndrew Yourtchenko      s[#s + 1] = json.stringify(v)
104b868e4eaSAndrew Yourtchenko    end
105b868e4eaSAndrew Yourtchenko    s[#s + 1] = '}'
106b868e4eaSAndrew Yourtchenko  elseif kind == 'string' then
107b868e4eaSAndrew Yourtchenko    return '"' .. escape_str(obj) .. '"'
108b868e4eaSAndrew Yourtchenko  elseif kind == 'number' then
109b868e4eaSAndrew Yourtchenko    if as_key then return '"' .. tostring(obj) .. '"' end
110b868e4eaSAndrew Yourtchenko    return tostring(obj)
111b868e4eaSAndrew Yourtchenko  elseif kind == 'boolean' then
112b868e4eaSAndrew Yourtchenko    return tostring(obj)
113b868e4eaSAndrew Yourtchenko  elseif kind == 'nil' then
114b868e4eaSAndrew Yourtchenko    return 'null'
115b868e4eaSAndrew Yourtchenko  else
116b868e4eaSAndrew Yourtchenko    error('Unjsonifiable type: ' .. kind .. '.')
117b868e4eaSAndrew Yourtchenko  end
118b868e4eaSAndrew Yourtchenko  return table.concat(s)
119b868e4eaSAndrew Yourtchenkoend
120b868e4eaSAndrew Yourtchenko
121b868e4eaSAndrew Yourtchenkojson.null = {}  -- This is a one-off table to represent the null value.
122b868e4eaSAndrew Yourtchenko
123b868e4eaSAndrew Yourtchenkofunction json.parse(str, pos, end_delim)
124b868e4eaSAndrew Yourtchenko  pos = pos or 1
125b868e4eaSAndrew Yourtchenko  if pos > #str then error('Reached unexpected end of input.') end
126b868e4eaSAndrew Yourtchenko  local pos = pos + #str:match('^%s*', pos)  -- Skip whitespace.
127b868e4eaSAndrew Yourtchenko  local first = str:sub(pos, pos)
128b868e4eaSAndrew Yourtchenko  if first == '{' then  -- Parse an object.
129b868e4eaSAndrew Yourtchenko    local obj, key, delim_found = {}, true, true
130b868e4eaSAndrew Yourtchenko    pos = pos + 1
131b868e4eaSAndrew Yourtchenko    while true do
132b868e4eaSAndrew Yourtchenko      key, pos = json.parse(str, pos, '}')
133b868e4eaSAndrew Yourtchenko      if key == nil then return obj, pos end
134b868e4eaSAndrew Yourtchenko      if not delim_found then error('Comma missing between object items.') end
135b868e4eaSAndrew Yourtchenko      pos = skip_delim(str, pos, ':', true)  -- true -> error if missing.
136b868e4eaSAndrew Yourtchenko      obj[key], pos = json.parse(str, pos)
137b868e4eaSAndrew Yourtchenko      pos, delim_found = skip_delim(str, pos, ',')
138b868e4eaSAndrew Yourtchenko    end
139b868e4eaSAndrew Yourtchenko  elseif first == '[' then  -- Parse an array.
140b868e4eaSAndrew Yourtchenko    local arr, val, delim_found = {}, true, true
141b868e4eaSAndrew Yourtchenko    pos = pos + 1
142b868e4eaSAndrew Yourtchenko    while true do
143b868e4eaSAndrew Yourtchenko      val, pos = json.parse(str, pos, ']')
144b868e4eaSAndrew Yourtchenko      if val == nil then return arr, pos end
145b868e4eaSAndrew Yourtchenko      if not delim_found then error('Comma missing between array items.') end
146b868e4eaSAndrew Yourtchenko      arr[#arr + 1] = val
147b868e4eaSAndrew Yourtchenko      pos, delim_found = skip_delim(str, pos, ',')
148b868e4eaSAndrew Yourtchenko    end
149b868e4eaSAndrew Yourtchenko  elseif first == '"' then  -- Parse a string.
150b868e4eaSAndrew Yourtchenko    return parse_str_val(str, pos + 1)
151b868e4eaSAndrew Yourtchenko  elseif first == '-' or first:match('%d') then  -- Parse a number.
152b868e4eaSAndrew Yourtchenko    return parse_num_val(str, pos)
153b868e4eaSAndrew Yourtchenko  elseif first == end_delim then  -- End of an object or array.
154b868e4eaSAndrew Yourtchenko    return nil, pos + 1
155b868e4eaSAndrew Yourtchenko  else  -- Parse true, false, or null.
156b868e4eaSAndrew Yourtchenko    local literals = {['true'] = true, ['false'] = false, ['null'] = json.null}
157b868e4eaSAndrew Yourtchenko    for lit_str, lit_val in pairs(literals) do
158b868e4eaSAndrew Yourtchenko      local lit_end = pos + #lit_str - 1
159b868e4eaSAndrew Yourtchenko      if str:sub(pos, lit_end) == lit_str then return lit_val, lit_end + 1 end
160b868e4eaSAndrew Yourtchenko    end
161b868e4eaSAndrew Yourtchenko    local pos_info_str = 'position ' .. pos .. ': ' .. str:sub(pos, pos + 10)
162b868e4eaSAndrew Yourtchenko    error('Invalid json syntax starting at ' .. pos_info_str)
163b868e4eaSAndrew Yourtchenko  end
164b868e4eaSAndrew Yourtchenkoend
165b868e4eaSAndrew Yourtchenko
166b868e4eaSAndrew Yourtchenko
167fa1456a3SAndrew Yourtchenkolocal vpp = {}
168fa1456a3SAndrew Yourtchenko
169fa1456a3SAndrew Yourtchenkolocal ffi = require("ffi")
170fa1456a3SAndrew Yourtchenko
171fa1456a3SAndrew Yourtchenko--[[
172fa1456a3SAndrew Yourtchenko
173fa1456a3SAndrew YourtchenkoThe basic type definitions. A bit of weird gymnastic with
174fa1456a3SAndrew Yourtchenkounionization of the hton* and ntoh* functions results
175fa1456a3SAndrew Yourtchenkois to make handling of signed and unsigned types a bit cleaner,
176fa1456a3SAndrew Yourtchenkoessentially building typecasting into a C union.
177fa1456a3SAndrew Yourtchenko
178fa1456a3SAndrew YourtchenkoThe vl_api_opaque_message_t is a synthetic type assumed to have
179fa1456a3SAndrew Yourtchenkoenough storage to hold the entire API message regardless of the type.
180fa1456a3SAndrew YourtchenkoDuring the operation it is casted to the specific message struct types.
181fa1456a3SAndrew Yourtchenko
182fa1456a3SAndrew Yourtchenko]]
183fa1456a3SAndrew Yourtchenko
184fa1456a3SAndrew Yourtchenko
185fa1456a3SAndrew Yourtchenkoffi.cdef([[
186fa1456a3SAndrew Yourtchenko
187fa1456a3SAndrew Yourtchenkotypedef uint8_t u8;
188fa1456a3SAndrew Yourtchenkotypedef int8_t i8;
189fa1456a3SAndrew Yourtchenkotypedef uint16_t u16;
190fa1456a3SAndrew Yourtchenkotypedef int16_t i16;
191fa1456a3SAndrew Yourtchenkotypedef uint32_t u32;
192fa1456a3SAndrew Yourtchenkotypedef int32_t i32;
193fa1456a3SAndrew Yourtchenkotypedef uint64_t u64;
194fa1456a3SAndrew Yourtchenkotypedef int64_t i64;
195fa1456a3SAndrew Yourtchenkotypedef double f64;
196fa1456a3SAndrew Yourtchenkotypedef float f32;
197fa1456a3SAndrew Yourtchenko
198fa1456a3SAndrew Yourtchenko#pragma pack(1)
199fa1456a3SAndrew Yourtchenkotypedef union {
200fa1456a3SAndrew Yourtchenko  u16 u16;
201fa1456a3SAndrew Yourtchenko  i16 i16;
202fa1456a3SAndrew Yourtchenko} lua_ui16t;
203fa1456a3SAndrew Yourtchenko
204fa1456a3SAndrew Yourtchenko#pragma pack(1)
205fa1456a3SAndrew Yourtchenkotypedef union {
206fa1456a3SAndrew Yourtchenko  u32 u32;
207fa1456a3SAndrew Yourtchenko  i32 i32;
208fa1456a3SAndrew Yourtchenko} lua_ui32t;
209fa1456a3SAndrew Yourtchenko
210fa1456a3SAndrew Yourtchenkou16 ntohs(uint16_t hostshort);
211fa1456a3SAndrew Yourtchenkou16 htons(uint16_t hostshort);
212fa1456a3SAndrew Yourtchenkou32 htonl(uint32_t along);
213fa1456a3SAndrew Yourtchenkou32 ntohl(uint32_t along);
214fa1456a3SAndrew Yourtchenkovoid *memset(void *s, int c, size_t n);
215fa1456a3SAndrew Yourtchenkovoid *memcpy(void *dest, void *src, size_t n);
216fa1456a3SAndrew Yourtchenko
217fa1456a3SAndrew Yourtchenko#pragma pack(1)
218fa1456a3SAndrew Yourtchenkotypedef struct _vl_api_opaque_message {
219fa1456a3SAndrew Yourtchenko  u16 _vl_msg_id;
220fa1456a3SAndrew Yourtchenko  u8  data[65536];
221fa1456a3SAndrew Yourtchenko} vl_api_opaque_message_t;
222fa1456a3SAndrew Yourtchenko]])
223fa1456a3SAndrew Yourtchenko
224fa1456a3SAndrew Yourtchenko
225fa1456a3SAndrew Yourtchenko-- CRC-based version stuff
226fa1456a3SAndrew Yourtchenko
227fa1456a3SAndrew Yourtchenkolocal crc32c_table = ffi.new('const uint32_t[256]',
228fa1456a3SAndrew Yourtchenko  { 0x00000000, 0xF26B8303, 0xE13B70F7, 0x1350F3F4,
229fa1456a3SAndrew Yourtchenko  0xC79A971F, 0x35F1141C, 0x26A1E7E8, 0xD4CA64EB,
230fa1456a3SAndrew Yourtchenko  0x8AD958CF, 0x78B2DBCC, 0x6BE22838, 0x9989AB3B,
231fa1456a3SAndrew Yourtchenko  0x4D43CFD0, 0xBF284CD3, 0xAC78BF27, 0x5E133C24,
232fa1456a3SAndrew Yourtchenko  0x105EC76F, 0xE235446C, 0xF165B798, 0x030E349B,
233fa1456a3SAndrew Yourtchenko  0xD7C45070, 0x25AFD373, 0x36FF2087, 0xC494A384,
234fa1456a3SAndrew Yourtchenko  0x9A879FA0, 0x68EC1CA3, 0x7BBCEF57, 0x89D76C54,
235fa1456a3SAndrew Yourtchenko  0x5D1D08BF, 0xAF768BBC, 0xBC267848, 0x4E4DFB4B,
236fa1456a3SAndrew Yourtchenko  0x20BD8EDE, 0xD2D60DDD, 0xC186FE29, 0x33ED7D2A,
237fa1456a3SAndrew Yourtchenko  0xE72719C1, 0x154C9AC2, 0x061C6936, 0xF477EA35,
238fa1456a3SAndrew Yourtchenko  0xAA64D611, 0x580F5512, 0x4B5FA6E6, 0xB93425E5,
239fa1456a3SAndrew Yourtchenko  0x6DFE410E, 0x9F95C20D, 0x8CC531F9, 0x7EAEB2FA,
240fa1456a3SAndrew Yourtchenko  0x30E349B1, 0xC288CAB2, 0xD1D83946, 0x23B3BA45,
241fa1456a3SAndrew Yourtchenko  0xF779DEAE, 0x05125DAD, 0x1642AE59, 0xE4292D5A,
242fa1456a3SAndrew Yourtchenko  0xBA3A117E, 0x4851927D, 0x5B016189, 0xA96AE28A,
243fa1456a3SAndrew Yourtchenko  0x7DA08661, 0x8FCB0562, 0x9C9BF696, 0x6EF07595,
244fa1456a3SAndrew Yourtchenko  0x417B1DBC, 0xB3109EBF, 0xA0406D4B, 0x522BEE48,
245fa1456a3SAndrew Yourtchenko  0x86E18AA3, 0x748A09A0, 0x67DAFA54, 0x95B17957,
246fa1456a3SAndrew Yourtchenko  0xCBA24573, 0x39C9C670, 0x2A993584, 0xD8F2B687,
247fa1456a3SAndrew Yourtchenko  0x0C38D26C, 0xFE53516F, 0xED03A29B, 0x1F682198,
248fa1456a3SAndrew Yourtchenko  0x5125DAD3, 0xA34E59D0, 0xB01EAA24, 0x42752927,
249fa1456a3SAndrew Yourtchenko  0x96BF4DCC, 0x64D4CECF, 0x77843D3B, 0x85EFBE38,
250fa1456a3SAndrew Yourtchenko  0xDBFC821C, 0x2997011F, 0x3AC7F2EB, 0xC8AC71E8,
251fa1456a3SAndrew Yourtchenko  0x1C661503, 0xEE0D9600, 0xFD5D65F4, 0x0F36E6F7,
252fa1456a3SAndrew Yourtchenko  0x61C69362, 0x93AD1061, 0x80FDE395, 0x72966096,
253fa1456a3SAndrew Yourtchenko  0xA65C047D, 0x5437877E, 0x4767748A, 0xB50CF789,
254fa1456a3SAndrew Yourtchenko  0xEB1FCBAD, 0x197448AE, 0x0A24BB5A, 0xF84F3859,
255fa1456a3SAndrew Yourtchenko  0x2C855CB2, 0xDEEEDFB1, 0xCDBE2C45, 0x3FD5AF46,
256fa1456a3SAndrew Yourtchenko  0x7198540D, 0x83F3D70E, 0x90A324FA, 0x62C8A7F9,
257fa1456a3SAndrew Yourtchenko  0xB602C312, 0x44694011, 0x5739B3E5, 0xA55230E6,
258fa1456a3SAndrew Yourtchenko  0xFB410CC2, 0x092A8FC1, 0x1A7A7C35, 0xE811FF36,
259fa1456a3SAndrew Yourtchenko  0x3CDB9BDD, 0xCEB018DE, 0xDDE0EB2A, 0x2F8B6829,
260fa1456a3SAndrew Yourtchenko  0x82F63B78, 0x709DB87B, 0x63CD4B8F, 0x91A6C88C,
261fa1456a3SAndrew Yourtchenko  0x456CAC67, 0xB7072F64, 0xA457DC90, 0x563C5F93,
262fa1456a3SAndrew Yourtchenko  0x082F63B7, 0xFA44E0B4, 0xE9141340, 0x1B7F9043,
263fa1456a3SAndrew Yourtchenko  0xCFB5F4A8, 0x3DDE77AB, 0x2E8E845F, 0xDCE5075C,
264fa1456a3SAndrew Yourtchenko  0x92A8FC17, 0x60C37F14, 0x73938CE0, 0x81F80FE3,
265fa1456a3SAndrew Yourtchenko  0x55326B08, 0xA759E80B, 0xB4091BFF, 0x466298FC,
266fa1456a3SAndrew Yourtchenko  0x1871A4D8, 0xEA1A27DB, 0xF94AD42F, 0x0B21572C,
267fa1456a3SAndrew Yourtchenko  0xDFEB33C7, 0x2D80B0C4, 0x3ED04330, 0xCCBBC033,
268fa1456a3SAndrew Yourtchenko  0xA24BB5A6, 0x502036A5, 0x4370C551, 0xB11B4652,
269fa1456a3SAndrew Yourtchenko  0x65D122B9, 0x97BAA1BA, 0x84EA524E, 0x7681D14D,
270fa1456a3SAndrew Yourtchenko  0x2892ED69, 0xDAF96E6A, 0xC9A99D9E, 0x3BC21E9D,
271fa1456a3SAndrew Yourtchenko  0xEF087A76, 0x1D63F975, 0x0E330A81, 0xFC588982,
272fa1456a3SAndrew Yourtchenko  0xB21572C9, 0x407EF1CA, 0x532E023E, 0xA145813D,
273fa1456a3SAndrew Yourtchenko  0x758FE5D6, 0x87E466D5, 0x94B49521, 0x66DF1622,
274fa1456a3SAndrew Yourtchenko  0x38CC2A06, 0xCAA7A905, 0xD9F75AF1, 0x2B9CD9F2,
275fa1456a3SAndrew Yourtchenko  0xFF56BD19, 0x0D3D3E1A, 0x1E6DCDEE, 0xEC064EED,
276fa1456a3SAndrew Yourtchenko  0xC38D26C4, 0x31E6A5C7, 0x22B65633, 0xD0DDD530,
277fa1456a3SAndrew Yourtchenko  0x0417B1DB, 0xF67C32D8, 0xE52CC12C, 0x1747422F,
278fa1456a3SAndrew Yourtchenko  0x49547E0B, 0xBB3FFD08, 0xA86F0EFC, 0x5A048DFF,
279fa1456a3SAndrew Yourtchenko  0x8ECEE914, 0x7CA56A17, 0x6FF599E3, 0x9D9E1AE0,
280fa1456a3SAndrew Yourtchenko  0xD3D3E1AB, 0x21B862A8, 0x32E8915C, 0xC083125F,
281fa1456a3SAndrew Yourtchenko  0x144976B4, 0xE622F5B7, 0xF5720643, 0x07198540,
282fa1456a3SAndrew Yourtchenko  0x590AB964, 0xAB613A67, 0xB831C993, 0x4A5A4A90,
283fa1456a3SAndrew Yourtchenko  0x9E902E7B, 0x6CFBAD78, 0x7FAB5E8C, 0x8DC0DD8F,
284fa1456a3SAndrew Yourtchenko  0xE330A81A, 0x115B2B19, 0x020BD8ED, 0xF0605BEE,
285fa1456a3SAndrew Yourtchenko  0x24AA3F05, 0xD6C1BC06, 0xC5914FF2, 0x37FACCF1,
286fa1456a3SAndrew Yourtchenko  0x69E9F0D5, 0x9B8273D6, 0x88D28022, 0x7AB90321,
287fa1456a3SAndrew Yourtchenko  0xAE7367CA, 0x5C18E4C9, 0x4F48173D, 0xBD23943E,
288fa1456a3SAndrew Yourtchenko  0xF36E6F75, 0x0105EC76, 0x12551F82, 0xE03E9C81,
289fa1456a3SAndrew Yourtchenko  0x34F4F86A, 0xC69F7B69, 0xD5CF889D, 0x27A40B9E,
290fa1456a3SAndrew Yourtchenko  0x79B737BA, 0x8BDCB4B9, 0x988C474D, 0x6AE7C44E,
291fa1456a3SAndrew Yourtchenko  0xBE2DA0A5, 0x4C4623A6, 0x5F16D052, 0xAD7D5351 }
292fa1456a3SAndrew Yourtchenko);
293fa1456a3SAndrew Yourtchenko
294fa1456a3SAndrew Yourtchenkolocal function CRC8(crc, d)
295fa1456a3SAndrew Yourtchenko  return bit.bxor(bit.rshift(crc, 8), crc32c_table[bit.band(0xff, bit.bxor(crc, d))])
296fa1456a3SAndrew Yourtchenkoend
297fa1456a3SAndrew Yourtchenko
298fa1456a3SAndrew Yourtchenkolocal function CRC16(crc, d)
299fa1456a3SAndrew Yourtchenko  crc = CRC8(crc, bit.band(d, 0xFF))
300fa1456a3SAndrew Yourtchenko  d = bit.rshift(d, 8)
301fa1456a3SAndrew Yourtchenko  crc = CRC8(crc, bit.band(d, 0xFF))
302fa1456a3SAndrew Yourtchenko  return crc
303fa1456a3SAndrew Yourtchenkoend
304fa1456a3SAndrew Yourtchenko
305fa1456a3SAndrew Yourtchenkolocal function string_crc(str, crc)
306fa1456a3SAndrew Yourtchenko  for i=1,#str do
307fa1456a3SAndrew Yourtchenko    -- print("S", i, string.byte(str, i), string.char(string.byte(str, i)))
308fa1456a3SAndrew Yourtchenko    crc = CRC8(crc, string.byte(str, i))
309fa1456a3SAndrew Yourtchenko  end
310fa1456a3SAndrew Yourtchenko  return crc
311fa1456a3SAndrew Yourtchenkoend
312fa1456a3SAndrew Yourtchenko
313fa1456a3SAndrew Yourtchenkolocal tokens = {
314fa1456a3SAndrew Yourtchenko  { ["match"] =' ', ["act"]             = { }  },
315fa1456a3SAndrew Yourtchenko  { ["match"] ='\n', ["act"]             = { }  },
316fa1456a3SAndrew Yourtchenko  { ["match"] ="manual_endian", ["act"]  = { "NODE_MANUAL_ENDIAN", "MANUAL_ENDIAN",    276 } },
317fa1456a3SAndrew Yourtchenko  { ["match"] ="define", ["act"]         = { "NODE_DEFINE",        "DEFINE",           267 } },
318fa1456a3SAndrew Yourtchenko  { ["match"] ="dont_trace", ["act"]     = { "NODE_DONT_TRACE",    "DONT_TRACE",       279 } },
319fa1456a3SAndrew Yourtchenko  { ["match"] ="f64", ["act"]            = { "NODE_F64",           "PRIMTYPE",         string_crc } },
320fa1456a3SAndrew Yourtchenko  { ["match"] ="i16", ["act"]            = { "NODE_I16",           "PRIMTYPE",         string_crc } },
321fa1456a3SAndrew Yourtchenko  { ["match"] ="i32", ["act"]            = { "NODE_I32",           "PRIMTYPE",         string_crc } },
322fa1456a3SAndrew Yourtchenko  { ["match"] ="i64", ["act"]            = { "NODE_I64",           "PRIMTYPE",         string_crc } },
323fa1456a3SAndrew Yourtchenko  { ["match"] ="i8", ["act"]             = { "NODE_I8",            "PRIMTYPE",         string_crc } },
324fa1456a3SAndrew Yourtchenko  { ["match"] ="manual_print", ["act"]   = { "NODE_MANUAL_PRINT",  "MANUAL_PRINT",     275 } },
325fa1456a3SAndrew Yourtchenko  { ["match"] ="noversion", ["act"]      = { "NODE_NOVERSION",     "NOVERSION",        274 } },
326fa1456a3SAndrew Yourtchenko  { ["match"] ="packed", ["act"]         = { "NODE_PACKED",        "TPACKED",          266 } },
327fa1456a3SAndrew Yourtchenko  { ["match"] ="typeonly", ["act"]       = { "NODE_TYPEONLY",      "TYPEONLY",         278 } },
328fa1456a3SAndrew Yourtchenko  { ["match"] ="u16", ["act"]            = { "NODE_U16",           "PRIMTYPE",         string_crc } },
329fa1456a3SAndrew Yourtchenko  { ["match"] ="u32", ["act"]            = { "NODE_U32",           "PRIMTYPE",         string_crc } },
330fa1456a3SAndrew Yourtchenko  { ["match"] ="u64", ["act"]            = { "NODE_U64",           "PRIMTYPE",         string_crc } },
331fa1456a3SAndrew Yourtchenko  { ["match"] ="u8", ["act"]             = { "NODE_U8",            "PRIMTYPE",         string_crc } },
332fa1456a3SAndrew Yourtchenko  { ["match"] ="union", ["act"]          = { "NODE_UNION",         "UNION",            271 } },
333fa1456a3SAndrew Yourtchenko  { ["match"] ="uword", ["act"]          = { "NODE_UWORD",         "PRIMTYPE",         string_crc } },
334fa1456a3SAndrew Yourtchenko  { ["match"] ="%(", ["act"]             = { "NODE_LPAR",          "LPAR",             259 } },
335fa1456a3SAndrew Yourtchenko  { ["match"] ="%)", ["act"]             = { "NODE_RPAR",          "RPAR",             258 } },
336fa1456a3SAndrew Yourtchenko  { ["match"] =";", ["act"]              = { "NODE_SEMI",          "SEMI",             260 } },
337fa1456a3SAndrew Yourtchenko  { ["match"] ="%[", ["act"]             = { "NODE_LBRACK",        "LBRACK",           261 } },
338fa1456a3SAndrew Yourtchenko  { ["match"] ="%]", ["act"]             = { "NODE_RBRACK",        "RBRACK",           262 } },
339fa1456a3SAndrew Yourtchenko  { ["match"] ="%{", ["act"]             = { "NODE_LCURLY",        "LCURLY",           268 } },
340fa1456a3SAndrew Yourtchenko  { ["match"] ="%}", ["act"]             = { "NODE_RCURLY",        "RCURLY",           269 } },
341fa1456a3SAndrew Yourtchenko  { ["match"] ='%b""', ["act"]           = { "NODE_STRING",        "STRING",           string_crc } },
342fa1456a3SAndrew Yourtchenko  { ["match"] ='%b@@', ["act"]           = { "NODE_HELPER",        "HELPER_STRING",    string_crc } },
343fa1456a3SAndrew Yourtchenko  -- TODO: \ must be consumed
344fa1456a3SAndrew Yourtchenko  { ["match"] ='[_a-zA-Z][_a-zA-Z0-9]*',
345fa1456a3SAndrew Yourtchenko                       ["act"]           = { "NODE_NAME",          "NAME",             string_crc } },
346fa1456a3SAndrew Yourtchenko  { ["match"] ='[0-9]+', ["act"]         = { "NODE_NUMBER",        "NUMBER",           string_crc } },
347fa1456a3SAndrew Yourtchenko  { ["match"] ='#[^\n]+', ["act"]            = { "NODE_PRAGMA",        "PRAGMA",           nil } },
348fa1456a3SAndrew Yourtchenko}
349fa1456a3SAndrew Yourtchenko
350fa1456a3SAndrew Yourtchenko
351fa1456a3SAndrew Yourtchenkofunction vpp.crc_version_string(data)
352fa1456a3SAndrew Yourtchenko  local input_crc = 0
353fa1456a3SAndrew Yourtchenko  -- Get rid of comments
354fa1456a3SAndrew Yourtchenko  data = data:gsub("/%*.-%*/", "")
355fa1456a3SAndrew Yourtchenko  data = data:gsub("//[^\n]+", "")
356fa1456a3SAndrew Yourtchenko  -- print(data)
357fa1456a3SAndrew Yourtchenko  idx = 1
358fa1456a3SAndrew Yourtchenko  while (true) do
359fa1456a3SAndrew Yourtchenko    local matched = nil
360fa1456a3SAndrew Yourtchenko    for k, v in ipairs(tokens) do
361fa1456a3SAndrew Yourtchenko      if not matched then
362fa1456a3SAndrew Yourtchenko        local x, y, cap = string.find(data, v["match"], idx)
363fa1456a3SAndrew Yourtchenko        if x == idx then
364fa1456a3SAndrew Yourtchenko          matched = { ["node"] = v["act"], ["x"] = x, ["y"] = y, ["cap"] = cap, ["chars"] = string.sub(data, x, y)  }
365fa1456a3SAndrew Yourtchenko          -- print(k, v, x, y, cap, matched.chars, matched.node[0] )
366fa1456a3SAndrew Yourtchenko        end
367fa1456a3SAndrew Yourtchenko      end
368fa1456a3SAndrew Yourtchenko    end
369fa1456a3SAndrew Yourtchenko    if matched then
370fa1456a3SAndrew Yourtchenko      idx = idx + (matched.y - matched.x + 1)
371fa1456a3SAndrew Yourtchenko      if matched.node[1] then
372fa1456a3SAndrew Yourtchenko        local act = matched.node[3]
373fa1456a3SAndrew Yourtchenko        if type(act) == "function" then
374fa1456a3SAndrew Yourtchenko          input_crc = act(matched.chars, input_crc)
375fa1456a3SAndrew Yourtchenko        elseif type(act) == "number" then
376fa1456a3SAndrew Yourtchenko          input_crc = CRC16(input_crc, act)
377fa1456a3SAndrew Yourtchenko        end
378fa1456a3SAndrew Yourtchenko        -- print(vpp.dump(matched))
379fa1456a3SAndrew Yourtchenko      end
380fa1456a3SAndrew Yourtchenko    else
381fa1456a3SAndrew Yourtchenko      -- print("NOT MATCHED!")
382fa1456a3SAndrew Yourtchenko      local crc = CRC16(input_crc, 0xFFFFFFFF)
383fa1456a3SAndrew Yourtchenko      return string.sub(string.format("%x", crc), -8)
384fa1456a3SAndrew Yourtchenko    end
385fa1456a3SAndrew Yourtchenko  end
386fa1456a3SAndrew Yourtchenkoend
387fa1456a3SAndrew Yourtchenko
388fa1456a3SAndrew Yourtchenko
389fa1456a3SAndrew Yourtchenkofunction vpp.dump(o)
390fa1456a3SAndrew Yourtchenko   if type(o) == 'table' then
391fa1456a3SAndrew Yourtchenko      local s = '{ '
392fa1456a3SAndrew Yourtchenko      for k,v in pairs(o) do
393fa1456a3SAndrew Yourtchenko         if type(k) ~= 'number' then k = '"'..k..'"' end
394fa1456a3SAndrew Yourtchenko         s = s .. '['..k..'] = ' .. vpp.dump(v) .. ','
395fa1456a3SAndrew Yourtchenko      end
396fa1456a3SAndrew Yourtchenko      return s .. '} '
397fa1456a3SAndrew Yourtchenko   else
398fa1456a3SAndrew Yourtchenko      return tostring(o)
399fa1456a3SAndrew Yourtchenko   end
400fa1456a3SAndrew Yourtchenkoend
401fa1456a3SAndrew Yourtchenko
402fa1456a3SAndrew Yourtchenkofunction vpp.hex_dump(buf)
403fa1456a3SAndrew Yourtchenko  local ret = {}
404fa1456a3SAndrew Yourtchenko  for i=1,math.ceil(#buf/16) * 16 do
405fa1456a3SAndrew Yourtchenko    if (i-1) % 16 == 0 then table.insert(ret, string.format('%08X  ', i-1)) end
406fa1456a3SAndrew Yourtchenko    table.insert(ret, ( i > #buf and '   ' or string.format('%02X ', buf:byte(i)) ))
407fa1456a3SAndrew Yourtchenko    if i %  8 == 0 then table.insert(ret, ' ') end
408fa1456a3SAndrew Yourtchenko    if i % 16 == 0 then table.insert(ret, buf:sub(i-16+1, i):gsub('%c','.')..'\n' ) end
409fa1456a3SAndrew Yourtchenko  end
410fa1456a3SAndrew Yourtchenko  return table.concat(ret)
411fa1456a3SAndrew Yourtchenkoend
412fa1456a3SAndrew Yourtchenko
413fa1456a3SAndrew Yourtchenko
414fa1456a3SAndrew Yourtchenkofunction vpp.c_str(text_in)
415fa1456a3SAndrew Yourtchenko  local text = text_in -- \000 will be helpfully added by ffi.copy
416fa1456a3SAndrew Yourtchenko  local c_str = ffi.new("char[?]", #text+1)
417fa1456a3SAndrew Yourtchenko  ffi.copy(c_str, text)
418fa1456a3SAndrew Yourtchenko  return c_str
419fa1456a3SAndrew Yourtchenkoend
420fa1456a3SAndrew Yourtchenko
421fa1456a3SAndrew Yourtchenko
422fa1456a3SAndrew Yourtchenkofunction vpp.init(vpp, args)
4235fec1e8bSDamjan Marion  local vac_api = args.vac_api or [[
4245fec1e8bSDamjan Marion int cough_vac_attach(char *vac_path, char *cough_path);
4255fec1e8bSDamjan Marion int vac_connect(char *name, char *chroot_prefix, void *cb);
4265fec1e8bSDamjan Marion int vac_disconnect(void);
4275fec1e8bSDamjan Marion int vac_read(char **data, int *l);
4285fec1e8bSDamjan Marion int vac_write(char *data, int len);
4295fec1e8bSDamjan Marion void vac_free(char *data);
4305fec1e8bSDamjan Marion uint32_t vac_get_msg_index(unsigned char * name);
431fa1456a3SAndrew Yourtchenko]]
432fa1456a3SAndrew Yourtchenko
4335fec1e8bSDamjan Marion  vpp.vac_path = args.vac_path
4345fec1e8bSDamjan Marion  ffi.cdef(vac_api)
435fa1456a3SAndrew Yourtchenko  local init_res = 0
4365fec1e8bSDamjan Marion  vpp.vac = ffi.load(vpp.vac_path)
437fa1456a3SAndrew Yourtchenko  if (init_res < 0) then
438fa1456a3SAndrew Yourtchenko    return nil
439fa1456a3SAndrew Yourtchenko  end
440fa1456a3SAndrew Yourtchenko
441fa1456a3SAndrew Yourtchenko  vpp.next_msg_num = 1
442fa1456a3SAndrew Yourtchenko  vpp.msg_name_to_number = {}
443fa1456a3SAndrew Yourtchenko  vpp.msg_name_to_fields = {}
444fa1456a3SAndrew Yourtchenko  vpp.msg_number_to_name = {}
445fa1456a3SAndrew Yourtchenko  vpp.msg_number_to_type = {}
446fa1456a3SAndrew Yourtchenko  vpp.msg_number_to_pointer_type = {}
447b868e4eaSAndrew Yourtchenko  vpp.msg_name_to_crc = {}
448fa1456a3SAndrew Yourtchenko  vpp.c_type_to_fields = {}
449fa1456a3SAndrew Yourtchenko  vpp.events = {}
450fa1456a3SAndrew Yourtchenko  vpp.plugin_version = {}
451fa1456a3SAndrew Yourtchenko  vpp.is_connected = false
452fa1456a3SAndrew Yourtchenko
453fa1456a3SAndrew Yourtchenko
454fa1456a3SAndrew Yourtchenko  vpp.t_lua2c = {}
455fa1456a3SAndrew Yourtchenko  vpp.t_c2lua = {}
456fa1456a3SAndrew Yourtchenko  vpp.t_lua2c["u8"] = function(c_type, src, dst_c_ptr)
457fa1456a3SAndrew Yourtchenko    if type(src) == "string" then
458fa1456a3SAndrew Yourtchenko      -- ffi.copy adds a zero byte at the end. Grrr.
459fa1456a3SAndrew Yourtchenko      -- ffi.copy(dst_c_ptr, src)
460fa1456a3SAndrew Yourtchenko      ffi.C.memcpy(dst_c_ptr, vpp.c_str(src), #src)
461fa1456a3SAndrew Yourtchenko      return(#src)
462fa1456a3SAndrew Yourtchenko    elseif type(src) == "table" then
463fa1456a3SAndrew Yourtchenko      for i,v in ipairs(src) do
464fa1456a3SAndrew Yourtchenko        ffi.cast("u8 *", dst_c_ptr)[i-1] = v
465fa1456a3SAndrew Yourtchenko      end
466fa1456a3SAndrew Yourtchenko      return(#src)
467fa1456a3SAndrew Yourtchenko    else
468fa1456a3SAndrew Yourtchenko      return 1, src -- ffi.cast("u8", src)
469fa1456a3SAndrew Yourtchenko    end
470fa1456a3SAndrew Yourtchenko  end
471fa1456a3SAndrew Yourtchenko  vpp.t_c2lua["u8"] = function(c_type, src_ptr, src_len)
472fa1456a3SAndrew Yourtchenko    if src_len then
473fa1456a3SAndrew Yourtchenko      return ffi.string(src_ptr, src_len)
474fa1456a3SAndrew Yourtchenko    else
475fa1456a3SAndrew Yourtchenko      return (tonumber(src_ptr))
476fa1456a3SAndrew Yourtchenko    end
477fa1456a3SAndrew Yourtchenko  end
478fa1456a3SAndrew Yourtchenko
479fa1456a3SAndrew Yourtchenko  vpp.t_lua2c["u16"] = function(c_type, src, dst_c_ptr)
480fa1456a3SAndrew Yourtchenko    if type(src) == "table" then
481fa1456a3SAndrew Yourtchenko      for i,v in ipairs(src) do
482fa1456a3SAndrew Yourtchenko        ffi.cast("u16 *", dst_c_ptr)[i-1] = ffi.C.htons(v)
483fa1456a3SAndrew Yourtchenko      end
484fa1456a3SAndrew Yourtchenko      return(2 * #src)
485fa1456a3SAndrew Yourtchenko    else
486fa1456a3SAndrew Yourtchenko      return 2, (ffi.C.htons(src))
487fa1456a3SAndrew Yourtchenko    end
488fa1456a3SAndrew Yourtchenko  end
489fa1456a3SAndrew Yourtchenko  vpp.t_c2lua["u16"] = function(c_type, src_ptr, src_len)
490fa1456a3SAndrew Yourtchenko    if src_len then
491fa1456a3SAndrew Yourtchenko      local out = {}
492fa1456a3SAndrew Yourtchenko      for i = 0,src_len-1 do
493fa1456a3SAndrew Yourtchenko        out[i+1] = tonumber(ffi.C.ntohs(src_ptr[i]))
494fa1456a3SAndrew Yourtchenko      end
495fa1456a3SAndrew Yourtchenko      return out
496fa1456a3SAndrew Yourtchenko    else
497fa1456a3SAndrew Yourtchenko      return (tonumber(ffi.C.ntohs(src_ptr)))
498fa1456a3SAndrew Yourtchenko    end
499fa1456a3SAndrew Yourtchenko  end
500fa1456a3SAndrew Yourtchenko
501fa1456a3SAndrew Yourtchenko  vpp.t_lua2c["u32"] = function(c_type, src, dst_c_ptr)
502fa1456a3SAndrew Yourtchenko    if type(src) == "table" then
503fa1456a3SAndrew Yourtchenko      for i,v in ipairs(src) do
504fa1456a3SAndrew Yourtchenko        ffi.cast("u32 *", dst_c_ptr)[i-1] = ffi.C.htonl(v)
505fa1456a3SAndrew Yourtchenko      end
506fa1456a3SAndrew Yourtchenko      return(4 * #src)
507fa1456a3SAndrew Yourtchenko    else
508fa1456a3SAndrew Yourtchenko      return 4, (ffi.C.htonl(src))
509fa1456a3SAndrew Yourtchenko    end
510fa1456a3SAndrew Yourtchenko  end
511fa1456a3SAndrew Yourtchenko  vpp.t_c2lua["u32"] = function(c_type, src_ptr, src_len)
512fa1456a3SAndrew Yourtchenko    if src_len then
513fa1456a3SAndrew Yourtchenko      local out = {}
514fa1456a3SAndrew Yourtchenko      for i = 0,src_len-1 do
515fa1456a3SAndrew Yourtchenko        out[i+1] = tonumber(ffi.C.ntohl(src_ptr[i]))
516fa1456a3SAndrew Yourtchenko      end
517fa1456a3SAndrew Yourtchenko      return out
518fa1456a3SAndrew Yourtchenko    else
519fa1456a3SAndrew Yourtchenko      return (tonumber(ffi.C.ntohl(src_ptr)))
520fa1456a3SAndrew Yourtchenko    end
521fa1456a3SAndrew Yourtchenko  end
522fa1456a3SAndrew Yourtchenko  vpp.t_lua2c["i32"] = function(c_type, src, dst_c_ptr)
523fa1456a3SAndrew Yourtchenko    if type(src) == "table" then
524fa1456a3SAndrew Yourtchenko      for i,v in ipairs(src) do
525fa1456a3SAndrew Yourtchenko        ffi.cast("i32 *", dst_c_ptr)[i-1] = ffi.C.htonl(v)
526fa1456a3SAndrew Yourtchenko      end
527fa1456a3SAndrew Yourtchenko      return(4 * #src)
528fa1456a3SAndrew Yourtchenko    else
529fa1456a3SAndrew Yourtchenko      return 4, (ffi.C.htonl(src))
530fa1456a3SAndrew Yourtchenko    end
531fa1456a3SAndrew Yourtchenko  end
532fa1456a3SAndrew Yourtchenko  vpp.t_c2lua["i32"] = function(c_type, src_ptr, src_len)
533fa1456a3SAndrew Yourtchenko    local ntohl = function(src)
534fa1456a3SAndrew Yourtchenko      local u32val = ffi.cast("u32", src)
535fa1456a3SAndrew Yourtchenko      local ntohlval = (ffi.C.ntohl(u32val))
536fa1456a3SAndrew Yourtchenko      local out = tonumber(ffi.cast("i32", ntohlval + 0LL))
537fa1456a3SAndrew Yourtchenko      return out
538fa1456a3SAndrew Yourtchenko    end
539fa1456a3SAndrew Yourtchenko    if src_len then
540fa1456a3SAndrew Yourtchenko      local out = {}
541fa1456a3SAndrew Yourtchenko      for i = 0,src_len-1 do
542fa1456a3SAndrew Yourtchenko        out[i+1] = tonumber(ntohl(src_ptr[i]))
543fa1456a3SAndrew Yourtchenko      end
544fa1456a3SAndrew Yourtchenko    else
545fa1456a3SAndrew Yourtchenko      return (tonumber(ntohl(src_ptr)))
546fa1456a3SAndrew Yourtchenko    end
547fa1456a3SAndrew Yourtchenko  end
548fa1456a3SAndrew Yourtchenko
549fa1456a3SAndrew Yourtchenko  vpp.t_lua2c["u64"] = function(c_type, src, dst_c_ptr)
550fa1456a3SAndrew Yourtchenko    if type(src) == "table" then
551fa1456a3SAndrew Yourtchenko      for i,v in ipairs(src) do
552fa1456a3SAndrew Yourtchenko        ffi.cast("u64 *", dst_c_ptr)[i-1] = v --- FIXME ENDIAN
553fa1456a3SAndrew Yourtchenko      end
554fa1456a3SAndrew Yourtchenko      return(8 * #src)
555fa1456a3SAndrew Yourtchenko    else
556fa1456a3SAndrew Yourtchenko      return 8, ffi.cast("u64", src) --- FIXME ENDIAN
557fa1456a3SAndrew Yourtchenko    end
558fa1456a3SAndrew Yourtchenko  end
559fa1456a3SAndrew Yourtchenko  vpp.t_c2lua["u64"] = function(c_type, src_ptr, src_len)
560fa1456a3SAndrew Yourtchenko    if src_len then
561fa1456a3SAndrew Yourtchenko      local out = {}
562fa1456a3SAndrew Yourtchenko      for i = 0,src_len-1 do
563fa1456a3SAndrew Yourtchenko        out[i+1] = tonumber(src_ptr[i]) -- FIXME ENDIAN
564fa1456a3SAndrew Yourtchenko      end
565fa1456a3SAndrew Yourtchenko      return out
566fa1456a3SAndrew Yourtchenko    else
567fa1456a3SAndrew Yourtchenko      return (tonumber(src_ptr)) --FIXME ENDIAN
568fa1456a3SAndrew Yourtchenko    end
569fa1456a3SAndrew Yourtchenko  end
570fa1456a3SAndrew Yourtchenko
571fa1456a3SAndrew Yourtchenko
572fa1456a3SAndrew Yourtchenko
573fa1456a3SAndrew Yourtchenko
574fa1456a3SAndrew Yourtchenko  vpp.t_lua2c["__MSG__"] = function(c_type, src, dst_c_ptr)
575fa1456a3SAndrew Yourtchenko    local dst = ffi.cast(c_type .. " *", dst_c_ptr)
576fa1456a3SAndrew Yourtchenko    local additional_len = 0
577fa1456a3SAndrew Yourtchenko    local fields_info = vpp.c_type_to_fields[c_type]
578fa1456a3SAndrew Yourtchenko    -- print("__MSG__ type: " .. tostring(c_type))
579fa1456a3SAndrew Yourtchenko    ffi.C.memset(dst_c_ptr, 0, ffi.sizeof(dst[0]))
580fa1456a3SAndrew Yourtchenko    -- print(vpp.dump(fields_info))
581fa1456a3SAndrew Yourtchenko    -- print(vpp.dump(src))
582fa1456a3SAndrew Yourtchenko    for k,v in pairs(src) do
583fa1456a3SAndrew Yourtchenko      local field = fields_info[k]
584fa1456a3SAndrew Yourtchenko      if not field then
585fa1456a3SAndrew Yourtchenko        print("ERROR: field " .. tostring(k) .. " in message " .. tostring(c_type) .. " is unknown")
586fa1456a3SAndrew Yourtchenko      end
587fa1456a3SAndrew Yourtchenko      local lua2c = vpp.t_lua2c[field.c_type]
588fa1456a3SAndrew Yourtchenko      -- print("__MSG__ field " .. tostring(k) .. " : " .. vpp.dump(field))
589fa1456a3SAndrew Yourtchenko      -- if the field is not an array type, try to coerce the argument to a number
590fa1456a3SAndrew Yourtchenko      if not field.array and type(v) == "string" then
591fa1456a3SAndrew Yourtchenko        v = tonumber(v)
592fa1456a3SAndrew Yourtchenko      end
593fa1456a3SAndrew Yourtchenko      if not lua2c then
594fa1456a3SAndrew Yourtchenko        print("__MSG__ " .. tostring(c_type) .. " t_lua2c: can not store field " .. field.name ..
595fa1456a3SAndrew Yourtchenko              " type " .. field.c_type .. " dst " .. tostring(dst[k]))
596fa1456a3SAndrew Yourtchenko        return 0
597fa1456a3SAndrew Yourtchenko      end
598fa1456a3SAndrew Yourtchenko      local len = 0
599fa1456a3SAndrew Yourtchenko      local val = nil
600fa1456a3SAndrew Yourtchenko      if field.array and (type(v) == "table") then
601985f3d11SAndrew Yourtchenko        -- print("NTFY: field " .. tostring(k) .. " in message " .. tostring(c_type) .. " is an array")
602fa1456a3SAndrew Yourtchenko        for field_i, field_v in ipairs(v) do
603985f3d11SAndrew Yourtchenko          -- print("NTFY: setting member#" .. tostring(field_i) .. " to value " .. vpp.dump(field_v))
604fa1456a3SAndrew Yourtchenko          local field_len, field_val = lua2c(field.c_type, field_v, dst[k][field_i-1])
605fa1456a3SAndrew Yourtchenko          len = len + field_len
606fa1456a3SAndrew Yourtchenko        end
607fa1456a3SAndrew Yourtchenko      else
608fa1456a3SAndrew Yourtchenko        len, val = lua2c(field.c_type, v, dst[k])
609fa1456a3SAndrew Yourtchenko      end
610fa1456a3SAndrew Yourtchenko      if not field.array then
611fa1456a3SAndrew Yourtchenko        dst[k] = val
612fa1456a3SAndrew Yourtchenko      else
613fa1456a3SAndrew Yourtchenko        if 0 == field.array then
614fa1456a3SAndrew Yourtchenko          additional_len = additional_len + len
615fa1456a3SAndrew Yourtchenko          -- print("Adding " .. tostring(len) .. " bytes due to field " .. tostring(field.name))
616fa1456a3SAndrew Yourtchenko          -- If there is a variable storing the length
617fa1456a3SAndrew Yourtchenko          -- and the input table does not set it, do magic
618fa1456a3SAndrew Yourtchenko          if field.array_size and not src[field.array_size] then
619fa1456a3SAndrew Yourtchenko            local size_field = fields_info[field.array_size]
620fa1456a3SAndrew Yourtchenko            if size_field then
621fa1456a3SAndrew Yourtchenko              dst[field.array_size] = vpp.t_c2lua[size_field.c_type](size_field.c_type, len)
622fa1456a3SAndrew Yourtchenko            end
623fa1456a3SAndrew Yourtchenko          end
624fa1456a3SAndrew Yourtchenko        end
625fa1456a3SAndrew Yourtchenko      end
626fa1456a3SAndrew Yourtchenko      -- print("Full message:\n" .. vpp.hex_dump(ffi.string(ffi.cast('void *', req_store_cache), 64)))
627fa1456a3SAndrew Yourtchenko    end
628fa1456a3SAndrew Yourtchenko    return (ffi.sizeof(dst[0])+additional_len)
629fa1456a3SAndrew Yourtchenko  end
630fa1456a3SAndrew Yourtchenko
631fa1456a3SAndrew Yourtchenko  vpp.t_c2lua["__MSG__"] = function(c_type, src_ptr, src_len)
632fa1456a3SAndrew Yourtchenko    local out = {}
633fa1456a3SAndrew Yourtchenko    local reply_typed_ptr = ffi.cast(c_type .. " *", src_ptr)
634fa1456a3SAndrew Yourtchenko    local field_desc = vpp.c_type_to_fields[c_type]
635fa1456a3SAndrew Yourtchenko    if src_len then
636fa1456a3SAndrew Yourtchenko      for i = 0,src_len-1 do
637fa1456a3SAndrew Yourtchenko        out[i+1] = vpp.t_c2lua[c_type](c_type, src_ptr[i])
638fa1456a3SAndrew Yourtchenko      end
639fa1456a3SAndrew Yourtchenko      return out
640fa1456a3SAndrew Yourtchenko    end
641fa1456a3SAndrew Yourtchenko
642fa1456a3SAndrew Yourtchenko    for k, v in pairs(field_desc) do
643fa1456a3SAndrew Yourtchenko      local v_c2lua = vpp.t_c2lua[v.c_type]
644fa1456a3SAndrew Yourtchenko      if v_c2lua then
645fa1456a3SAndrew Yourtchenko        local len = v.array
646fa1456a3SAndrew Yourtchenko        -- print(dump(v))
647fa1456a3SAndrew Yourtchenko        if len then
648fa1456a3SAndrew Yourtchenko          local len_field_name = k .. "_length"
649fa1456a3SAndrew Yourtchenko          local len_field = field_desc[len_field_name]
650fa1456a3SAndrew Yourtchenko          if (len_field) then
651fa1456a3SAndrew Yourtchenko            local real_len = vpp.t_c2lua[len_field.c_type](len_field.c_type, reply_typed_ptr[len_field_name])
652fa1456a3SAndrew Yourtchenko            out[k] =  v_c2lua(v.c_type, reply_typed_ptr[k], real_len)
653fa1456a3SAndrew Yourtchenko          elseif len == 0 then
654fa1456a3SAndrew Yourtchenko            -- check if len = 0, then must be a field which contains the size
655fa1456a3SAndrew Yourtchenko            len_field =  field_desc[v.array_size]
656fa1456a3SAndrew Yourtchenko            local real_len = vpp.t_c2lua[len_field.c_type](len_field.c_type, reply_typed_ptr[v.array_size])
657fa1456a3SAndrew Yourtchenko            -- print("REAL length: " .. vpp.dump(v) .. " : " .. tostring(real_len))
658fa1456a3SAndrew Yourtchenko            out[k] = v_c2lua(v.c_type, reply_typed_ptr[k], real_len)
659fa1456a3SAndrew Yourtchenko          else
660fa1456a3SAndrew Yourtchenko            -- alas, just stuff the entire array
661fa1456a3SAndrew Yourtchenko            out[k] = v_c2lua(v.c_type, reply_typed_ptr[k], len)
662fa1456a3SAndrew Yourtchenko          end
663fa1456a3SAndrew Yourtchenko        else
664fa1456a3SAndrew Yourtchenko          out[k] =  v_c2lua(v.c_type, reply_typed_ptr[k])
665fa1456a3SAndrew Yourtchenko        end
666fa1456a3SAndrew Yourtchenko      else
667fa1456a3SAndrew Yourtchenko        out[k] = "<no accessor function for type " .. tostring(v.c_type) .. ">"
668fa1456a3SAndrew Yourtchenko      end
669fa1456a3SAndrew Yourtchenko      -- print(k, out[k])
670fa1456a3SAndrew Yourtchenko    end
671fa1456a3SAndrew Yourtchenko    return out
672fa1456a3SAndrew Yourtchenko  end
673fa1456a3SAndrew Yourtchenko
674fa1456a3SAndrew Yourtchenko  return vpp
675fa1456a3SAndrew Yourtchenkoend
676fa1456a3SAndrew Yourtchenko
677b868e4eaSAndrew Yourtchenkofunction vpp.resolve_message_number(msgname)
678b868e4eaSAndrew Yourtchenko  local name = msgname .. "_" .. vpp.msg_name_to_crc[msgname]
6795fec1e8bSDamjan Marion  local idx = vpp.vac.vac_get_msg_index(vpp.c_str(name))
680b868e4eaSAndrew Yourtchenko  if vpp.debug_dump then
681b868e4eaSAndrew Yourtchenko    print("Index for " .. tostring(name) .. " is " .. tostring(idx))
682b868e4eaSAndrew Yourtchenko  end
683b868e4eaSAndrew Yourtchenko  vpp.msg_name_to_number[msgname] = idx
684b868e4eaSAndrew Yourtchenko  vpp.msg_number_to_name[idx] = msgname
685b868e4eaSAndrew Yourtchenko  vpp.msg_number_to_type[idx] = "vl_api_" .. msgname .. "_t"
686b868e4eaSAndrew Yourtchenko  vpp.msg_number_to_pointer_type[idx] = vpp.msg_number_to_type[idx] .. " *"
687b868e4eaSAndrew Yourtchenko  ffi.cdef("\n\n enum { vl_msg_" .. msgname .. " = " .. idx .. " };\n\n")
688b868e4eaSAndrew Yourtchenkoend
689b868e4eaSAndrew Yourtchenko
690fa1456a3SAndrew Yourtchenkofunction vpp.connect(vpp, client_name)
691fa1456a3SAndrew Yourtchenko    local name = "lua_client"
692fa1456a3SAndrew Yourtchenko    if client_name then
693fa1456a3SAndrew Yourtchenko      name = client_name
694fa1456a3SAndrew Yourtchenko    end
6955fec1e8bSDamjan Marion    local ret = vpp.vac.vac_connect(vpp.c_str(client_name), nil, nil)
696fa1456a3SAndrew Yourtchenko    if tonumber(ret) == 0 then
697fa1456a3SAndrew Yourtchenko      vpp.is_connected = true
698fa1456a3SAndrew Yourtchenko    end
699b868e4eaSAndrew Yourtchenko    for k, v in pairs(vpp.msg_name_to_number) do
700b868e4eaSAndrew Yourtchenko      vpp.resolve_message_number(k)
701b868e4eaSAndrew Yourtchenko    end
702fa1456a3SAndrew Yourtchenko  end
703fa1456a3SAndrew Yourtchenko
704fa1456a3SAndrew Yourtchenkofunction vpp.disconnect(vpp)
7055fec1e8bSDamjan Marion    vpp.vac.vac_disconnect()
706fa1456a3SAndrew Yourtchenko  end
707fa1456a3SAndrew Yourtchenko
708b868e4eaSAndrew Yourtchenkofunction vpp.json_api(vpp, path, plugin_name)
709b868e4eaSAndrew Yourtchenko    -- print("Consuming the VPP api from "..path)
710b868e4eaSAndrew Yourtchenko    local ffii = {}
711b868e4eaSAndrew Yourtchenko    local f = io.open(path, "r")
712b868e4eaSAndrew Yourtchenko    if not f then
713b868e4eaSAndrew Yourtchenko      print("Could not open " .. path)
714b868e4eaSAndrew Yourtchenko      return nil
715b868e4eaSAndrew Yourtchenko    end
716b868e4eaSAndrew Yourtchenko    local data = f:read("*all")
717b868e4eaSAndrew Yourtchenko    local json = json.parse(data)
718b868e4eaSAndrew Yourtchenko    if not (json.types or json.messages) then
719b868e4eaSAndrew Yourtchenko      print("Can not parse " .. path)
720b868e4eaSAndrew Yourtchenko      return nil
721b868e4eaSAndrew Yourtchenko    end
722b868e4eaSAndrew Yourtchenko
723b868e4eaSAndrew Yourtchenko    local all_types = {}
724b868e4eaSAndrew Yourtchenko
725b868e4eaSAndrew Yourtchenko    for i, v in ipairs(json.types) do
726b868e4eaSAndrew Yourtchenko      table.insert(all_types, { typeonly = 1, desc = v })
727b868e4eaSAndrew Yourtchenko    end
728b868e4eaSAndrew Yourtchenko    for i, v in ipairs(json.messages) do
729b868e4eaSAndrew Yourtchenko      table.insert(all_types, { typeonly = 0, desc = v })
730b868e4eaSAndrew Yourtchenko    end
731b868e4eaSAndrew Yourtchenko    for i, v in ipairs(all_types) do
732b868e4eaSAndrew Yourtchenko      local typeonly = v.typeonly
733b868e4eaSAndrew Yourtchenko      local name = v.desc[1]
734b868e4eaSAndrew Yourtchenko      local c_type = "vl_api_" .. name .. "_t"
735b868e4eaSAndrew Yourtchenko
736b868e4eaSAndrew Yourtchenko      local fields = {}
737b868e4eaSAndrew Yourtchenko      -- vpp.msg_name_to_fields[name] = fields
738b868e4eaSAndrew Yourtchenko      -- print("CTYPE " .. c_type)
739b868e4eaSAndrew Yourtchenko      vpp.c_type_to_fields[c_type] = fields
740b868e4eaSAndrew Yourtchenko      vpp.t_lua2c[c_type] = vpp.t_lua2c["__MSG__"]
741b868e4eaSAndrew Yourtchenko      vpp.t_c2lua[c_type] = vpp.t_c2lua["__MSG__"]
742b868e4eaSAndrew Yourtchenko
743b868e4eaSAndrew Yourtchenko      local cdef = { "\n\n#pragma pack(1)\ntypedef struct _vl_api_", name, " {\n" }
744b868e4eaSAndrew Yourtchenko      for ii, vv in ipairs(v.desc) do
745b868e4eaSAndrew Yourtchenko        if type(vv) == "table" then
746b868e4eaSAndrew Yourtchenko          if vv.crc then
747b868e4eaSAndrew Yourtchenko            vpp.msg_name_to_crc[name] = string.sub(vv.crc, 3) -- strip the leading 0x
748b868e4eaSAndrew Yourtchenko          else
749b868e4eaSAndrew Yourtchenko            local fieldtype = vv[1]
750b868e4eaSAndrew Yourtchenko            local fieldname = vv[2]
751b868e4eaSAndrew Yourtchenko            local fieldcount = vv[3]
752b868e4eaSAndrew Yourtchenko            local fieldcountvar = vv[4]
753b868e4eaSAndrew Yourtchenko            local fieldrec = { name = fieldname, c_type = fieldtype, array = fieldcount, array_size = fieldcountvar }
754b868e4eaSAndrew Yourtchenko            if fieldcount then
755b868e4eaSAndrew Yourtchenko              table.insert(cdef, "  " .. fieldtype .. " " .. fieldname .. "[" .. fieldcount .. "];\n")
756b868e4eaSAndrew Yourtchenko              if fieldtype == "u8" then
757b868e4eaSAndrew Yourtchenko                -- any array of bytes is treated as a string
758b868e4eaSAndrew Yourtchenko              elseif vpp.t_lua2c[fieldtype] then
759b868e4eaSAndrew Yourtchenko                -- print("Array of " .. fieldtype .. " is ok!")
760b868e4eaSAndrew Yourtchenko              else
761b868e4eaSAndrew Yourtchenko                print("Unknown array type: ", name,  " : " , fieldname, " : ", fieldtype, ":", fieldcount, ":", fieldcountvar)
762b868e4eaSAndrew Yourtchenko              end
763b868e4eaSAndrew Yourtchenko            else
764b868e4eaSAndrew Yourtchenko              table.insert(cdef, "  " .. fieldtype .. " " .. fieldname .. ";\n")
765b868e4eaSAndrew Yourtchenko            end
766b868e4eaSAndrew Yourtchenko            fields[fieldname] = fieldrec
767b868e4eaSAndrew Yourtchenko          end
768b868e4eaSAndrew Yourtchenko        end
769b868e4eaSAndrew Yourtchenko      end
770b868e4eaSAndrew Yourtchenko
771b868e4eaSAndrew Yourtchenko      table.insert(cdef, "} vl_api_" .. name .. "_t;")
772b868e4eaSAndrew Yourtchenko      table.insert(ffii, table.concat(cdef))
773b868e4eaSAndrew Yourtchenko
774b868e4eaSAndrew Yourtchenko      if typeonly == 0 then
775b868e4eaSAndrew Yourtchenko        -- we will want to resolve this later
776b868e4eaSAndrew Yourtchenko        if vpp.debug_dump then
777b868e4eaSAndrew Yourtchenko          print("Remember to resolve " .. name)
778b868e4eaSAndrew Yourtchenko        end
779b868e4eaSAndrew Yourtchenko        vpp.msg_name_to_number[name] = -1
780b868e4eaSAndrew Yourtchenko        if vpp.is_connected then
781b868e4eaSAndrew Yourtchenko          vpp.resolve_message_number(name)
782b868e4eaSAndrew Yourtchenko        end
783b868e4eaSAndrew Yourtchenko      end
784b868e4eaSAndrew Yourtchenko
785b868e4eaSAndrew Yourtchenko    end
786b868e4eaSAndrew Yourtchenko    local cdef_full = table.concat(ffii)
787b868e4eaSAndrew Yourtchenko    ffi.cdef(cdef_full)
788b868e4eaSAndrew Yourtchenkoend
789b868e4eaSAndrew Yourtchenko
790fa1456a3SAndrew Yourtchenkofunction vpp.consume_api(vpp, path, plugin_name)
791fa1456a3SAndrew Yourtchenko    -- print("Consuming the VPP api from "..path)
792fa1456a3SAndrew Yourtchenko    local ffii = {}
793fa1456a3SAndrew Yourtchenko    local f = io.open(path, "r")
794fa1456a3SAndrew Yourtchenko    if not f then
795fa1456a3SAndrew Yourtchenko      print("Could not open " .. path)
796fa1456a3SAndrew Yourtchenko      return nil
797fa1456a3SAndrew Yourtchenko    end
798fa1456a3SAndrew Yourtchenko    local data = f:read("*all")
799fa1456a3SAndrew Yourtchenko    -- Remove all C comments
800fa1456a3SAndrew Yourtchenko    data = data:gsub("/%*.-%*/", "")
801fa1456a3SAndrew Yourtchenko    if vpp.is_connected and not plugin_name then
802fa1456a3SAndrew Yourtchenko      print(path .. ": must specify plugin name!")
803fa1456a3SAndrew Yourtchenko      return
804fa1456a3SAndrew Yourtchenko    end
805fa1456a3SAndrew Yourtchenko    if plugin_name then
806fa1456a3SAndrew Yourtchenko      vpp.plugin_version[plugin_name] = vpp.crc_version_string(data)
807fa1456a3SAndrew Yourtchenko      local full_plugin_name = plugin_name .. "_" .. vpp.plugin_version[plugin_name]
808fa1456a3SAndrew Yourtchenko      local reply = vpp:api_call("get_first_msg_id", { name = full_plugin_name } )
809fa1456a3SAndrew Yourtchenko      vpp.next_msg_num = tonumber(reply[1].first_msg_id)
810fa1456a3SAndrew Yourtchenko      print("Plugin " .. full_plugin_name .. " first message is " .. tostring(vpp.next_msg_num))
811fa1456a3SAndrew Yourtchenko    end
812fa1456a3SAndrew Yourtchenko    -- print ("data len: ", #data)
813fa1456a3SAndrew Yourtchenko    data = data:gsub("\n(.-)(%S+)%s*{([^}]*)}", function (preamble, name, members)
814fa1456a3SAndrew Yourtchenko      local _, typeonly = preamble:gsub("typeonly", "")
815fa1456a3SAndrew Yourtchenko      local maybe_msg_id_field = { [0] = "u16 _vl_msg_id;", "" }
816fa1456a3SAndrew Yourtchenko      local onedef = "\n\n#pragma pack(1)\ntypedef struct _vl_api_"..name.. " {\n" ..
817fa1456a3SAndrew Yourtchenko	   -- "   u16 _vl_msg_id;" ..
818fa1456a3SAndrew Yourtchenko           maybe_msg_id_field[typeonly] ..
819fa1456a3SAndrew Yourtchenko	   members:gsub("%[[a-zA-Z_]+]", "[0]") ..
820fa1456a3SAndrew Yourtchenko	   "} vl_api_" .. name .. "_t;"
821fa1456a3SAndrew Yourtchenko
822fa1456a3SAndrew Yourtchenko      local c_type = "vl_api_" .. name .. "_t"
823fa1456a3SAndrew Yourtchenko
824fa1456a3SAndrew Yourtchenko      local fields = {}
825fa1456a3SAndrew Yourtchenko      -- vpp.msg_name_to_fields[name] = fields
826fa1456a3SAndrew Yourtchenko      -- print("CTYPE " .. c_type)
827fa1456a3SAndrew Yourtchenko      vpp.c_type_to_fields[c_type] = fields
828fa1456a3SAndrew Yourtchenko      vpp.t_lua2c[c_type] = vpp.t_lua2c["__MSG__"]
829fa1456a3SAndrew Yourtchenko      vpp.t_c2lua[c_type] = vpp.t_c2lua["__MSG__"]
830fa1456a3SAndrew Yourtchenko      local mirec = { name = "_vl_msg_id", c_type = "u16", array = nil, array_size = nil }
831fa1456a3SAndrew Yourtchenko      if typeonly == 0 then
832fa1456a3SAndrew Yourtchenko        fields[mirec.name] = mirec
833fa1456a3SAndrew Yourtchenko      end
834fa1456a3SAndrew Yourtchenko
835fa1456a3SAndrew Yourtchenko      -- populate the field reflection table for the message
836fa1456a3SAndrew Yourtchenko      -- sets the various type information as well as the accessors for lua<->C conversion
837fa1456a3SAndrew Yourtchenko      members:gsub("(%S+)%s+(%S+);", function (fieldtype, fieldname)
838fa1456a3SAndrew Yourtchenko          local fieldcount = nil
839fa1456a3SAndrew Yourtchenko          local fieldcountvar = nil
840fa1456a3SAndrew Yourtchenko          -- data = data:gsub("%[[a-zA-Z_]+]", "[0]")
841fa1456a3SAndrew Yourtchenko          fieldname = fieldname:gsub("(%b[])", function(cnt)
842fa1456a3SAndrew Yourtchenko              fieldcount = tonumber(cnt:sub(2, -2));
843fa1456a3SAndrew Yourtchenko              if not fieldcount then
844fa1456a3SAndrew Yourtchenko                fieldcount = 0
845fa1456a3SAndrew Yourtchenko                fieldcountvar = cnt:sub(2, -2)
846fa1456a3SAndrew Yourtchenko              end
847fa1456a3SAndrew Yourtchenko              return ""
848fa1456a3SAndrew Yourtchenko            end)
849fa1456a3SAndrew Yourtchenko	  local fieldrec = { name = fieldname, c_type = fieldtype, array = fieldcount, array_size = fieldcountvar }
850fa1456a3SAndrew Yourtchenko          if fieldcount then
851fa1456a3SAndrew Yourtchenko            if fieldtype == "u8" then
852fa1456a3SAndrew Yourtchenko              -- any array of bytes is treated as a string
853fa1456a3SAndrew Yourtchenko            elseif vpp.t_lua2c[fieldtype] then
854fa1456a3SAndrew Yourtchenko              -- print("Array of " .. fieldtype .. " is ok!")
855fa1456a3SAndrew Yourtchenko            else
856fa1456a3SAndrew Yourtchenko              print("Unknown array type: ", name,  " : " , fieldname, " : ", fieldtype, ":", fieldcount, ":", fieldcountvar)
857fa1456a3SAndrew Yourtchenko            end
858fa1456a3SAndrew Yourtchenko          end
859fa1456a3SAndrew Yourtchenko	  fields[fieldname] = fieldrec
860fa1456a3SAndrew Yourtchenko	end)
861fa1456a3SAndrew Yourtchenko
862fa1456a3SAndrew Yourtchenko      -- print(dump(fields))
863fa1456a3SAndrew Yourtchenko
864fa1456a3SAndrew Yourtchenko      if typeonly == 0 then
865fa1456a3SAndrew Yourtchenko	local this_message_number = vpp.next_msg_num
866fa1456a3SAndrew Yourtchenko	vpp.next_msg_num = vpp.next_msg_num + 1
867fa1456a3SAndrew Yourtchenko	vpp.msg_name_to_number[name] = this_message_number
868fa1456a3SAndrew Yourtchenko	vpp.msg_number_to_name[this_message_number] = name
869fa1456a3SAndrew Yourtchenko	vpp.msg_number_to_type[this_message_number] = "vl_api_" .. name .. "_t"
870fa1456a3SAndrew Yourtchenko	vpp.msg_number_to_pointer_type[this_message_number] = vpp.msg_number_to_type[this_message_number] .. " *"
871fa1456a3SAndrew Yourtchenko	onedef = onedef .. "\n\n enum { vl_msg_" .. name .. " = " .. this_message_number .. " };\n\n"
872fa1456a3SAndrew Yourtchenko      end
873fa1456a3SAndrew Yourtchenko      table.insert(ffii, onedef);
874fa1456a3SAndrew Yourtchenko      return "";
875fa1456a3SAndrew Yourtchenko      end)
876fa1456a3SAndrew Yourtchenko    local cdef = table.concat(ffii)
877fa1456a3SAndrew Yourtchenko    -- print(cdef)
878fa1456a3SAndrew Yourtchenko    ffi.cdef(cdef)
879fa1456a3SAndrew Yourtchenko  end
880fa1456a3SAndrew Yourtchenko
881fa1456a3SAndrew Yourtchenko
882fa1456a3SAndrew Yourtchenkofunction vpp.lua2c(vpp, c_type, src, dst_c_ptr)
883fa1456a3SAndrew Yourtchenko  -- returns the number of bytes written to memory pointed by dst
884fa1456a3SAndrew Yourtchenko  local lua2c = vpp.t_lua2c[c_type]
885fa1456a3SAndrew Yourtchenko  if lua2c then
886fa1456a3SAndrew Yourtchenko    return(lua2c(c_type, src, dst_c_ptr))
887fa1456a3SAndrew Yourtchenko  else
888b868e4eaSAndrew Yourtchenko    print("vpp.lua2c: do not know how to store type " .. tostring(c_type))
889b868e4eaSAndrew Yourtchenko    local x = "a" .. nil
890fa1456a3SAndrew Yourtchenko    return 0
891fa1456a3SAndrew Yourtchenko  end
892fa1456a3SAndrew Yourtchenkoend
893fa1456a3SAndrew Yourtchenko
894fa1456a3SAndrew Yourtchenkofunction vpp.c2lua(vpp, c_type, src_ptr, src_len)
895fa1456a3SAndrew Yourtchenko  -- returns the lua data structure
896fa1456a3SAndrew Yourtchenko  local c2lua = vpp.t_c2lua[c_type]
897fa1456a3SAndrew Yourtchenko  if c2lua then
898fa1456a3SAndrew Yourtchenko    return(c2lua(c_type, src_ptr, src_len))
899fa1456a3SAndrew Yourtchenko  else
900fa1456a3SAndrew Yourtchenko    print("vpp.c2lua: do not know how to load type " .. c_type)
901fa1456a3SAndrew Yourtchenko    return nil
902fa1456a3SAndrew Yourtchenko  end
903fa1456a3SAndrew Yourtchenkoend
904fa1456a3SAndrew Yourtchenko
905fa1456a3SAndrew Yourtchenkolocal req_store_cache = ffi.new("vl_api_opaque_message_t[1]")
906fa1456a3SAndrew Yourtchenko
907fa1456a3SAndrew Yourtchenkofunction vpp.api_write(vpp, api_name, req_table)
908fa1456a3SAndrew Yourtchenko    local msg_num = vpp.msg_name_to_number[api_name]
909fa1456a3SAndrew Yourtchenko    if not msg_num then
910fa1456a3SAndrew Yourtchenko      print ("API call "..api_name.." is not known")
911fa1456a3SAndrew Yourtchenko      return nil
912fa1456a3SAndrew Yourtchenko    end
913fa1456a3SAndrew Yourtchenko
914fa1456a3SAndrew Yourtchenko    if not req_table then
915fa1456a3SAndrew Yourtchenko      req_table = {}
916fa1456a3SAndrew Yourtchenko    end
917fa1456a3SAndrew Yourtchenko    req_table._vl_msg_id = msg_num
918fa1456a3SAndrew Yourtchenko
919fa1456a3SAndrew Yourtchenko    local packed_len = vpp:lua2c(vpp.msg_number_to_type[msg_num], req_table, req_store_cache)
920fa1456a3SAndrew Yourtchenko    if vpp.debug_dump then
921fa1456a3SAndrew Yourtchenko      print("Write Message length: " .. tostring(packed_len) .. "\n" .. vpp.hex_dump(ffi.string(ffi.cast('void *', req_store_cache), packed_len)))
922fa1456a3SAndrew Yourtchenko    end
923fa1456a3SAndrew Yourtchenko
9245fec1e8bSDamjan Marion    res = vpp.vac.vac_write(ffi.cast('void *', req_store_cache), packed_len)
925fa1456a3SAndrew Yourtchenko    return res
926fa1456a3SAndrew Yourtchenko  end
927fa1456a3SAndrew Yourtchenko
928fa1456a3SAndrew Yourtchenkolocal rep_store_cache = ffi.new("vl_api_opaque_message_t *[1]")
929fa1456a3SAndrew Yourtchenkolocal rep_len_cache = ffi.new("int[1]")
930fa1456a3SAndrew Yourtchenko
931fa1456a3SAndrew Yourtchenkofunction vpp.api_read(vpp)
932fa1456a3SAndrew Yourtchenko    local rep_type = "vl_api_opaque_message_t"
933fa1456a3SAndrew Yourtchenko    local rep = rep_store_cache
934fa1456a3SAndrew Yourtchenko    local replen = rep_len_cache
9355fec1e8bSDamjan Marion    res = vpp.vac.vac_read(ffi.cast("void *", rep), replen)
936fa1456a3SAndrew Yourtchenko    if vpp.debug_dump then
937fa1456a3SAndrew Yourtchenko      print("Read Message length: " .. tostring(replen[0]) .. "\n" .. vpp.hex_dump(ffi.string(ffi.cast('void *', rep[0]), replen[0])))
938fa1456a3SAndrew Yourtchenko    end
939fa1456a3SAndrew Yourtchenko
940fa1456a3SAndrew Yourtchenko    local reply_msg_num = ffi.C.ntohs(rep[0]._vl_msg_id)
941fa1456a3SAndrew Yourtchenko    local reply_msg_name = vpp.msg_number_to_name[reply_msg_num]
942fa1456a3SAndrew Yourtchenko
943fa1456a3SAndrew Yourtchenko    local reply_typed_ptr = ffi.cast(vpp.msg_number_to_pointer_type[reply_msg_num], rep[0])
944fa1456a3SAndrew Yourtchenko    local out = vpp:c2lua(vpp.msg_number_to_type[reply_msg_num], rep[0], nil, replen[0])
945fa1456a3SAndrew Yourtchenko    if type(out) == "table" then
946fa1456a3SAndrew Yourtchenko      out["luaapi_message_name"] = reply_msg_name
947fa1456a3SAndrew Yourtchenko    end
948fa1456a3SAndrew Yourtchenko
9495fec1e8bSDamjan Marion    vpp.vac.vac_free(ffi.cast('void *',rep[0]))
950fa1456a3SAndrew Yourtchenko
951fa1456a3SAndrew Yourtchenko    return reply_msg_name, out
952fa1456a3SAndrew Yourtchenko  end
953fa1456a3SAndrew Yourtchenko
954fa1456a3SAndrew Yourtchenkofunction vpp.api_call(vpp, api_name, req_table, options_in)
955fa1456a3SAndrew Yourtchenko    local msg_num = vpp.msg_name_to_number[api_name]
956fa1456a3SAndrew Yourtchenko    local end_message_name = api_name .."_reply"
957fa1456a3SAndrew Yourtchenko    local replies = {}
958fa1456a3SAndrew Yourtchenko    local cstruct = ""
959fa1456a3SAndrew Yourtchenko    local options = options_in or {}
960fa1456a3SAndrew Yourtchenko    if msg_num then
961b868e4eaSAndrew Yourtchenko      if vpp.debug_dump then
962b868e4eaSAndrew Yourtchenko        print("Message #" .. tostring(msg_num) .. " for name " .. tostring(api_name))
963b868e4eaSAndrew Yourtchenko      end
964fa1456a3SAndrew Yourtchenko      vpp:api_write(api_name, req_table)
965fa1456a3SAndrew Yourtchenko      if not vpp.msg_name_to_number[end_message_name] or options.force_ping then
966fa1456a3SAndrew Yourtchenko        end_message_name = "control_ping_reply"
967fa1456a3SAndrew Yourtchenko        vpp:api_write("control_ping")
968fa1456a3SAndrew Yourtchenko      end
969fa1456a3SAndrew Yourtchenko      repeat
970fa1456a3SAndrew Yourtchenko        reply_message_name, reply = vpp:api_read()
971fa1456a3SAndrew Yourtchenko        if reply and not reply.context then
972fa1456a3SAndrew Yourtchenko          -- there may be async events inbetween
973fa1456a3SAndrew Yourtchenko          table.insert(vpp.events, reply)
974fa1456a3SAndrew Yourtchenko        else
975fa1456a3SAndrew Yourtchenko          if reply_message_name ~= "control_ping_reply" then
976fa1456a3SAndrew Yourtchenko            -- do not insert the control ping encapsulation
977fa1456a3SAndrew Yourtchenko            table.insert(replies, reply)
978fa1456a3SAndrew Yourtchenko          end
979fa1456a3SAndrew Yourtchenko        end
980fa1456a3SAndrew Yourtchenko        -- print(reply)
981fa1456a3SAndrew Yourtchenko      until reply_message_name == end_message_name
982fa1456a3SAndrew Yourtchenko    else
983fa1456a3SAndrew Yourtchenko      print(api_name .. " is an unknown API call")
984fa1456a3SAndrew Yourtchenko      return nil
985fa1456a3SAndrew Yourtchenko    end
986fa1456a3SAndrew Yourtchenko    return replies
987fa1456a3SAndrew Yourtchenko  end
988fa1456a3SAndrew Yourtchenko
989fa1456a3SAndrew Yourtchenkoreturn vpp