vxlan: vxlan/vxlan.api API cleanup
[vpp.git] / extras / emacs / tunnel-c-skel.el
1 ;;; Copyright (c) 2016 Cisco and/or its affiliates.
2 ;;; Licensed under the Apache License, Version 2.0 (the "License");
3 ;;; you may not use this file except in compliance with the License.
4 ;;; You may obtain a copy of the License at:
5 ;;;
6 ;;;     http://www.apache.org/licenses/LICENSE-2.0
7 ;;;
8 ;;; Unless required by applicable law or agreed to in writing, software
9 ;;; distributed under the License is distributed on an "AS IS" BASIS,
10 ;;; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
11 ;;; See the License for the specific language governing permissions and
12 ;;; limitations under the License.
13
14 ;;; tunnel-c-skel.el - tunnel encap cli / api
15
16 (require 'skeleton)
17
18 (define-skeleton skel-tunnel-c
19 "Insert a tunnel cli/api implementation"
20 nil
21 '(setq encap_stack (skeleton-read "encap_stack (e.g ip4_udp_lisp): "))
22 '(setq ENCAP_STACK (upcase encap_stack))
23 '(setq encap-stack (replace-regexp-in-string "_" "-" encap_stack))
24 "
25 #include <vnet/" encap-stack "/" encap_stack" .h>
26
27 " encap_stack "_main_t " encap_stack "_main;
28
29 static u8 * format_decap_next (u8 * s, va_list * args)
30 {
31   u32 next_index = va_arg (*args, u32);
32
33   switch (next_index)
34     {
35     case " ENCAP_STACK "_INPUT_NEXT_DROP:
36       return format (s, \"drop\");
37     case " ENCAP_STACK "_INPUT_NEXT_IP4_INPUT:
38       return format (s, \"ip4\");
39     case " ENCAP_STACK "_INPUT_NEXT_IP6_INPUT:
40       return format (s, \"ip6\");
41     case " ENCAP_STACK "_INPUT_NEXT_" ENCAP_STACK "_ENCAP:
42       return format (s, \"" encap-stack "\");
43     default:
44       return format (s, \"unknown %d\", next_index);
45     }
46   return s;
47 }
48
49 u8 * format_" encap_stack "_tunnel (u8 * s, va_list * args)
50 {
51   " encap_stack "_tunnel_t * t = va_arg (*args, " encap_stack "_tunnel_t *);
52   " encap_stack "_main_t * ngm = &" encap_stack "_main;
53
54   s = format (s, 
55               \"[%d] %U (src) %U (dst) fibs: encap %d, decap %d\",
56               t - ngm->tunnels,
57               format_ip4_address, &t->src,
58               format_ip4_address, &t->dst,
59               t->encap_fib_index,
60               t->decap_fib_index);
61
62   s = format (s, \" decap next %U\\n\", format_decap_next, t->decap_next_index);
63   /* FIXME: add protocol details */
64   return s;
65 }
66
67 static u8 * format_" encap_stack "_name (u8 * s, va_list * args)
68 {
69   u32 dev_instance = va_arg (*args, u32);
70   return format (s, \"" encap_stack "_tunnel%d\", dev_instance);
71 }
72
73 static uword dummy_interface_tx (vlib_main_t * vm,
74                                  vlib_node_runtime_t * node,
75                                  vlib_frame_t * frame)
76 {
77   clib_warning (\"you shouldn't be here, leaking buffers...\");
78   return frame->n_vectors;
79 }
80
81 VNET_DEVICE_CLASS (" encap_stack "_device_class,static) = {
82   .name = "" ENCAP_STACK "",
83   .format_device_name = format_" encap_stack "_name,
84   .format_tx_trace = format_" encap_stack "_encap_trace,
85   .tx_function = dummy_interface_tx,
86 };
87
88 static uword dummy_set_rewrite (vnet_main_t * vnm,
89                                 u32 sw_if_index,
90                                 u32 l3_type,
91                                 void * dst_address,
92                                 void * rewrite,
93                                 uword max_rewrite_bytes)
94 {
95   return 0;
96 }
97
98 u8 * format_" encap_stack "_header_with_length (u8 * s, va_list * args)
99 {
100   " encap_stack "_header_t * h = va_arg (*args, " encap_stack "_header_t *);
101   u32 max_header_bytes = va_arg (*args, u32);
102   u32 header_bytes;
103
104   header_bytes = sizeof (h[0]);
105   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
106     return format (s, \"" encap-stack "header truncated\");
107
108   /* FIXME: pretty-print an " encap_stack " header */
109
110   return s;
111 }
112
113 VNET_HW_INTERFACE_CLASS (" encap_stack "_hw_class) = {
114   .name = \"" ENCAP_STACK "\",
115   .format_header = format_" encap_stack "_header_with_length,
116   .set_rewrite = dummy_set_rewrite,
117 };
118
119 #define foreach_copy_field                      \
120 _(src.as_u32)                                   \
121 _(dst.as_u32)                                   \
122 _(encap_fib_index)                              \
123 _(decap_fib_index)                              \
124 _(decap_next_index)                             \
125 _(FIXME_ADD_ALL_COPY_FIELDS )
126
127 static int " encap_stack "_rewrite (" encap_stack "_tunnel_t * t)
128 {
129   u8 *rw = 0;
130   ip4_header_t * ip0;
131   " encap_stack "_header_t * h0;
132   int len;
133
134   len = sizeof (*h0);
135
136   vec_validate_aligned (rw, len-1, CLIB_CACHE_LINE_BYTES);
137
138   h0 = (ip4_udp_" encap_stack "_header_t *) rw;
139
140   /* FIXME: build the actual header here... */
141
142   /* Fixed portion of the (outer) ip4 header */
143   ip0 = &h0->ip4;
144   ip0->ip_version_and_header_length = 0x45;
145   ip0->ttl = 254;
146   ip0->protocol = IP_PROTOCOL_UDP;
147
148   /* we'll fix up the ip4 header length and checksum after-the-fact */
149   ip0->src_address.as_u32 = t->src.as_u32;
150   ip0->dst_address.as_u32 = t->dst.as_u32;
151   ip0->checksum = ip4_header_checksum (ip0);
152
153   /* UDP header, randomize src port on something, maybe? */
154   h0->udp.src_port = clib_host_to_net_u16 (4341);
155   h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_" encap_stack ");
156
157   /* $$$ build a <mumble> tunnel header here */
158   
159   t->rewrite = rw;
160   return (0);
161 }
162
163 int vnet_" encap_stack "_add_del_tunnel 
164 (vnet_" encap_stack "_add_del_tunnel_args_t *a, u32 * hw_if_indexp)
165 {
166   " encap_stack "_main_t * ngm = &" encap_stack "_main;
167   " encap_stack "_tunnel_t *t = 0;
168   vnet_main_t * vnm = ngm->vnet_main;
169   vnet_hw_interface_t * hi;
170   uword * p;
171   u32 hw_if_index = ~0;
172   int rv;
173   " encap_stack "_tunnel_key_t key, *key_copy;
174   hash_pair_t *hp;
175   
176   key.FIXME = clib_host_to_net_XXX(FIXME);
177
178   p = hash_get_mem (ngm->" encap_stack "_tunnel_by_key, &key);
179   
180   if (a->is_add)
181     {
182       /* adding a tunnel: tunnel must not already exist */
183       if (p) 
184         return VNET_API_ERROR_INVALID_VALUE;
185       
186       pool_get_aligned (ngm->tunnels, t, CLIB_CACHE_LINE_BYTES);
187       memset (t, 0, sizeof (*t));
188       
189       /* copy from arg structure */
190 #define _(x) t->x = a->x;
191       foreach_copy_field;
192 #undef _
193       
194       rv = " encap_stack "_rewrite (t);
195
196       if (rv)
197         {
198           pool_put (ngm->tunnels, t);
199           return rv;
200         }
201
202       /* $$$$ use a simple hash if you can ... */
203       key_copy = clib_mem_alloc (sizeof (*key_copy));
204       clib_memcpy (key_copy, &key, sizeof (*key_copy));
205
206       hash_set_mem (ngm->" encap_stack "_tunnel_by_key, key_copy, 
207                     t - ngm->tunnels);
208       
209       /* 
210        * interface freelist / recycle shtik
211        * This simple implementation rapidly reuses freed tunnel interfaces.
212        * Consider whether to refcount, etc. etc.
213        */ 
214       if (vec_len (ngm->free_" encap_stack "_tunnel_hw_if_indices) > 0)
215         {
216           hw_if_index = ngm->free_" encap_stack "_tunnel_hw_if_indices
217             [vec_len (ngm->free_" encap_stack "_tunnel_hw_if_indices)-1];
218           _vec_len (ngm->free_" encap_stack "_tunnel_hw_if_indices) -= 1;
219           
220           hi = vnet_get_hw_interface (vnm, hw_if_index);
221           hi->dev_instance = t - ngm->tunnels;
222           hi->hw_instance = hi->dev_instance;
223         }
224       else 
225         {
226           hw_if_index = vnet_register_interface
227             (vnm, " encap_stack "_device_class.index, t - ngm->tunnels,
228              " encap_stack "_hw_class.index, t - ngm->tunnels);
229           hi = vnet_get_hw_interface (vnm, hw_if_index);
230           hi->output_node_index = " encap_stack "_encap_node.index;
231         }
232       
233       t->hw_if_index = hw_if_index;
234       
235       vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 
236                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
237     }
238   else
239     {
240       /* deleting a tunnel: tunnel must exist */
241       if (!p) 
242         return VNET_API_ERROR_NO_SUCH_ENTRY;
243
244       t = pool_elt_at_index (ngm->tunnels, p[0]);
245
246       vnet_sw_interface_set_flags (vnm, t->hw_if_index, 0 /* down */);
247       vec_add1 (ngm->free_" encap_stack "_tunnel_hw_if_indices, t->hw_if_index);
248
249       hp = hash_get_pair (ngm->" encap_stack "_tunnel_by_key, &key);
250       key_copy = (void *)(hp->key);
251       hash_unset_mem (ngm->" encap_stack "_tunnel_by_key, &key);
252       clib_mem_free (key_copy);
253
254       vec_free (t->rewrite);
255       pool_put (ngm->tunnels, t);
256     }
257
258   if (hw_if_indexp)
259       *hw_if_indexp = hw_if_index;
260
261   return 0;
262 }
263
264 static u32 fib_index_from_fib_id (u32 fib_id)
265 {
266   ip4_main_t * im = &ip4_main;
267   uword * p;
268
269   p = hash_get (im->fib_index_by_table_id, fib_id);
270   if (!p)
271     return ~0;
272
273   return p[0];
274 }
275
276 static uword unformat_decap_next (unformat_input_t * input, va_list * args)
277 {
278   u32 * result = va_arg (*args, u32 *);
279   u32 tmp;
280   
281   if (unformat (input, \"drop\"))
282     *result = " ENCAP_STACK "_INPUT_NEXT_DROP;
283   else if (unformat (input, \"ip4\"))
284     *result = " ENCAP_STACK "_INPUT_NEXT_IP4_INPUT;
285   else if (unformat (input, \"ip6\"))
286     *result = " ENCAP_STACK "_INPUT_NEXT_IP6_INPUT;
287   else if (unformat (input, \"ethernet\"))
288     *result = " ENCAP_STACK "_INPUT_NEXT_IP6_INPUT;
289   else if (unformat (input, \"" encap-stack "\"))
290     *result = " ENCAP_STACK "_INPUT_NEXT_" ENCAP_STACK "_ENCAP;
291   else if (unformat (input, \"%d\", &tmp))
292     *result = tmp;
293   else
294     return 0;
295   return 1;
296 }
297
298 static clib_error_t *
299 " encap_stack "_add_del_tunnel_command_fn (vlib_main_t * vm,
300                                    unformat_input_t * input,
301                                    vlib_cli_command_t * cmd)
302 {
303   unformat_input_t _line_input, * line_input = &_line_input;
304   clib_error_t *error = 0;
305   ip4_address_t src, dst;
306   u8 is_add = 1;
307   u8 src_set = 0;
308   u8 dst_set = 0;
309   u32 encap_fib_index = 0;
310   u32 decap_fib_index = 0;
311   u8 next_protocol = " ENCAP_STACK "_NEXT_PROTOCOL_IP4;
312   u32 decap_next_index = " ENCAP_STACK "_INPUT_NEXT_IP4_INPUT;
313   u8 flags = " ENCAP_STACK "_FLAGS_P;
314   u8 ver_res = 0;
315   u8 res = 0;
316   u32 iid = 0;
317   u8 iid_set = 0;
318   u32 tmp;
319   int rv;
320   vnet_" encap_stack "_add_del_tunnel_args_t _a, * a = &_a;
321   
322   /* Get a line of input. */
323   if (! unformat_user (input, unformat_line_input, line_input))
324     return 0;
325
326   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT) {
327     if (unformat (line_input, \"del\"))
328       is_add = 0;
329     else if (unformat (line_input, \"src %U\", 
330                        unformat_ip4_address, &src))
331       src_set = 1;
332     else if (unformat (line_input, \"dst %U\",
333                        unformat_ip4_address, &dst))
334       dst_set = 1;
335     else if (unformat (line_input, \"encap-vrf-id %d\", &tmp))
336       {
337         encap_fib_index = fib_index_from_fib_id (tmp);
338         if (encap_fib_index == ~0)
339           {
340             unformat_free (line_input);
341             return clib_error_return (0, \"nonexistent encap fib id %d\", tmp);
342           }
343       }
344     else if (unformat (line_input, \"decap-vrf-id %d\", &tmp))
345       {
346         decap_fib_index = fib_index_from_fib_id (tmp);
347         if (decap_fib_index == ~0)
348           {
349             unformat_free (line_input);
350             return clib_error_return (0, \"nonexistent decap fib id %d\", tmp);
351           }
352       }
353     else if (unformat (line_input, \"decap-next %U\", unformat_decap_next, 
354                        &decap_next_index))
355       ;
356     else if (unformat(line_input, \"next-ip4\"))
357       next_protocol = 1;
358     else if (unformat(line_input, \"next-ip6\"))
359       next_protocol = 2;
360     else if (unformat(line_input, \"next-ethernet\"))
361       next_protocol = 3;
362     else if (unformat(line_input, \"next-nsh\"))
363       next_protocol = 4;
364     /* 
365      * $$$ allow the user to specify anything they want 
366      * in the " ENCAP_STACK " header
367      */
368     else 
369       {
370         error = clib_error_return (0, \"parse error: '%U'\",
371                                    format_unformat_error, line_input);
372         unformat_free (line_input);
373         return error;
374       }
375   }
376
377   unformat_free (line_input);
378
379   if (src_set == 0)
380     return clib_error_return (0, \"tunnel src address not specified\");
381
382   if (dst_set == 0)
383     return clib_error_return (0, \"tunnel dst address not specified\");
384
385   memset (a, 0, sizeof (*a));
386
387   a->is_add = is_add;
388
389 #define _(x) a->x = x;
390   foreach_copy_field;
391 #undef _
392   
393   rv = vnet_" encap_stack "_add_del_tunnel (a, 0 /* hw_if_indexp */);
394
395   switch(rv)
396     {
397     case 0:
398       break;
399     case VNET_API_ERROR_INVALID_VALUE:
400       return clib_error_return (0, \"tunnel already exists...\");
401
402     case VNET_API_ERROR_NO_SUCH_ENTRY:
403       return clib_error_return (0, \"tunnel does not exist...\");
404
405     default:
406       return clib_error_return 
407         (0, \"vnet_" encap_stack "_add_del_tunnel returned %d\", rv);
408     }
409
410   return 0;
411 }
412
413 VLIB_CLI_COMMAND (create_" encap_stack "_tunnel_command, static) = {
414   .path = \"lisp gpe tunnel\",
415   .short_help = 
416   \"<mumble> tunnel src <ip4-addr> dst <ip4-addr>\\n\"
417   \"    [encap-fib-id <nn>] [decap-fib-id <nn>]\\n\"
418   \"    [decap-next [ip4|ip6|ethernet|nsh-encap|<nn>]][del]\\n\",
419   .function = " encap_stack "_add_del_tunnel_command_fn,
420 };
421
422 static clib_error_t *
423 show_" encap_stack "_tunnel_command_fn (vlib_main_t * vm,
424                                 unformat_input_t * input,
425                                 vlib_cli_command_t * cmd)
426 {
427   " encap_stack "_main_t * ngm = &" encap_stack "_main;
428   " encap_stack "_tunnel_t * t;
429   
430   if (pool_elts (ngm->tunnels) == 0)
431     vlib_cli_output (vm, \"No lisp-gpe tunnels configured...\");
432
433   pool_foreach (t, ngm->tunnels,
434   ({
435     vlib_cli_output (vm, \"%U\", format_" encap_stack "_tunnel);
436   }));
437   
438   return 0;
439 }
440
441 VLIB_CLI_COMMAND (show_" encap_stack "_tunnel_command, static) = {
442     .path = \"show lisp gpe tunnel\",
443     .function = show_" encap_stack "_tunnel_command_fn,
444 };
445
446 clib_error_t *" encap_stack "_init (vlib_main_t *vm)
447 {
448   " encap_stack "_main_t *ngm = &" encap_stack "_main;
449   
450   ngm->vnet_main = vnet_get_main();
451   ngm->vlib_main = vm;
452   
453   ngm->" encap_stack "_tunnel_by_key 
454     = hash_create_mem (0, sizeof(" encap_stack "_tunnel_key_t), sizeof (uword));
455
456   /* YMMV, register with the local netstack */
457   udp_register_dst_port (vm, UDP_DST_PORT_" encap_stack ", 
458                          " encap_stack "_input_node.index, 1 /* is_ip4 */);
459   return 0;
460 }
461
462 VLIB_INIT_FUNCTION(" encap_stack "_init);
463
464 ")
465