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