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