lisp: fix ip and udp checksum computation
[vpp.git] / src / plugins / lisp / lisp-gpe / interface.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15
16 /**
17  * @file
18  * @brief Common utility functions for LISP-GPE interfaces.
19  *
20  */
21
22 #include <vppinfra/error.h>
23 #include <vppinfra/hash.h>
24 #include <vnet/vnet.h>
25 #include <vnet/ip/ip.h>
26 #include <vnet/udp/udp_inlines.h>
27 #include <vnet/ethernet/ethernet.h>
28 #include <lisp/lisp-gpe/lisp_gpe.h>
29 #include <lisp/lisp-gpe/lisp_gpe_fwd_entry.h>
30 #include <lisp/lisp-gpe/lisp_gpe_tenant.h>
31 #include <lisp/lisp-gpe/lisp_gpe_adjacency.h>
32 #include <vnet/adj/adj.h>
33 #include <vnet/fib/fib_table.h>
34 #include <vnet/fib/ip4_fib.h>
35 #include <vnet/fib/ip6_fib.h>
36 #include <lisp/lisp-cp/lisp_cp_dpo.h>
37
38 /**
39  * @brief The VLIB node arc/edge from the interface's TX node, to the L2
40  * load-balanceing node. Which is where all packets go
41  */
42 static uword l2_arc_to_lb;
43
44 #define foreach_lisp_gpe_tx_next        \
45   _(DROP, "error-drop")                 \
46   _(IP4_LOOKUP, "ip4-lookup")           \
47   _(IP6_LOOKUP, "ip6-lookup")
48
49 typedef enum
50 {
51 #define _(sym,str) LISP_GPE_TX_NEXT_##sym,
52   foreach_lisp_gpe_tx_next
53 #undef _
54     LISP_GPE_TX_N_NEXT,
55 } lisp_gpe_tx_next_t;
56
57 typedef struct
58 {
59   u32 tunnel_index;
60 } lisp_gpe_tx_trace_t;
61
62 u8 *
63 format_lisp_gpe_tx_trace (u8 * s, va_list * args)
64 {
65   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
66   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
67   lisp_gpe_tx_trace_t *t = va_arg (*args, lisp_gpe_tx_trace_t *);
68
69   s = format (s, "LISP-GPE-TX: tunnel %d", t->tunnel_index);
70   return s;
71 }
72
73 #define is_v4_packet(_h) ((*(u8*) _h) & 0xF0) == 0x40
74
75 /**
76  * @brief LISP-GPE interface TX (encap) function.
77  * @node lisp_gpe_interface_tx
78  *
79  * The LISP-GPE interface TX (encap) function.
80  *
81  * Looks up the associated tunnel based on the adjacency hit in the SD FIB
82  * and if the tunnel is multihomed it uses the flow hash to determine
83  * sub-tunnel, and rewrite string, to be used to encapsulate the packet.
84  *
85  * @param[in]   vm      vlib_main_t corresponding to the current thread.
86  * @param[in]   node    vlib_node_runtime_t data for this node.
87  * @param[in]   frame   vlib_frame_t whose contents should be dispatched.
88  *
89  * @return number of vectors in frame.
90  */
91 VLIB_NODE_FN (lisp_tunnel_output)
92 (vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
93 {
94   u32 n_left_from, next_index, *from, *to_next;
95
96   from = vlib_frame_vector_args (from_frame);
97   n_left_from = from_frame->n_vectors;
98
99   next_index = node->cached_next_index;
100
101   while (n_left_from > 0)
102     {
103       u32 n_left_to_next;
104
105       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
106
107       while (n_left_from > 0 && n_left_to_next > 0)
108         {
109           u32 bi0, adj_index0, next0;
110           const ip_adjacency_t *adj0;
111           const dpo_id_t *dpo0;
112           vlib_buffer_t *b0;
113
114           bi0 = from[0];
115           to_next[0] = bi0;
116           from += 1;
117           to_next += 1;
118           n_left_from -= 1;
119           n_left_to_next -= 1;
120
121           b0 = vlib_get_buffer (vm, bi0);
122           b0->flags |= VNET_BUFFER_F_LOCALLY_ORIGINATED;
123
124           /* Follow the DPO on which the midchain is stacked */
125           adj_index0 = vnet_buffer (b0)->ip.adj_index[VLIB_TX];
126           adj0 = adj_get (adj_index0);
127           dpo0 = &adj0->sub_type.midchain.next_dpo;
128           next0 = dpo0->dpoi_next_node;
129           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
130
131           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
132             {
133               lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
134                                                         sizeof (*tr));
135               tr->tunnel_index = adj_index0;
136             }
137           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
138                                            n_left_to_next, bi0, next0);
139         }
140
141       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
142     }
143
144   return from_frame->n_vectors;
145 }
146
147 VLIB_REGISTER_NODE (lisp_tunnel_output) = {
148   .name = "lisp-tunnel-output",
149   .vector_size = sizeof (u32),
150   .format_trace = format_lisp_gpe_tx_trace,
151   .sibling_of = "tunnel-output",
152 };
153
154 static u8 *
155 format_lisp_gpe_name (u8 * s, va_list * args)
156 {
157   u32 dev_instance = va_arg (*args, u32);
158   return format (s, "lisp_gpe%d", dev_instance);
159 }
160
161 /* *INDENT-OFF* */
162 VNET_DEVICE_CLASS (lisp_gpe_device_class) = {
163   .name = "LISP_GPE",
164   .format_device_name = format_lisp_gpe_name,
165 };
166 /* *INDENT-ON* */
167
168 u8 *
169 format_lisp_gpe_header_with_length (u8 * s, va_list * args)
170 {
171   lisp_gpe_header_t *h = va_arg (*args, lisp_gpe_header_t *);
172   u32 max_header_bytes = va_arg (*args, u32);
173   u32 header_bytes;
174
175   header_bytes = sizeof (h[0]);
176   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
177     return format (s, "lisp-gpe header truncated");
178
179   s = format (s, "flags: ");
180 #define _(n,v) if (h->flags & v) s = format (s, "%s ", #n);
181   foreach_lisp_gpe_flag_bit;
182 #undef _
183
184   s = format (s, "\n  ver_res %d res %d next_protocol %d iid %d(%x)",
185               h->ver_res, h->res, h->next_protocol,
186               clib_net_to_host_u32 (h->iid << 8),
187               clib_net_to_host_u32 (h->iid << 8));
188   return s;
189 }
190
191 /* *INDENT-OFF* */
192 VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = {
193   .name = "LISP_GPE",
194   .format_header = format_lisp_gpe_header_with_length,
195   .build_rewrite = lisp_gpe_build_rewrite,
196   .update_adjacency = lisp_gpe_update_adjacency,
197 };
198 /* *INDENT-ON* */
199
200
201 typedef struct
202 {
203   u32 dpo_index;
204 } l2_lisp_gpe_tx_trace_t;
205
206 static u8 *
207 format_l2_lisp_gpe_tx_trace (u8 * s, va_list * args)
208 {
209   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
210   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
211   l2_lisp_gpe_tx_trace_t *t = va_arg (*args, l2_lisp_gpe_tx_trace_t *);
212
213   s = format (s, "L2-LISP-GPE-TX: load-balance %d", t->dpo_index);
214   return s;
215 }
216
217 /**
218  * @brief LISP-GPE interface TX (encap) function for L2 overlays.
219  * @node l2_lisp_gpe_interface_tx
220  *
221  * The L2 LISP-GPE interface TX (encap) function.
222  *
223  * Uses bridge domain index, source and destination ethernet addresses to
224  * lookup tunnel. If the tunnel is multihomed a flow has is used to determine
225  * the sub-tunnel and therefore the rewrite string to be used to encapsulate
226  * the packets.
227  *
228  * @param[in]   vm        vlib_main_t corresponding to the current thread.
229  * @param[in]   node      vlib_node_runtime_t data for this node.
230  * @param[in]   frame     vlib_frame_t whose contents should be dispatched.
231  *
232  * @return number of vectors in frame.
233  */
234 static uword
235 l2_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
236                           vlib_frame_t * from_frame)
237 {
238   u32 n_left_from, next_index, *from, *to_next;
239   lisp_gpe_main_t *lgm = &lisp_gpe_main;
240   u32 thread_index = vm->thread_index;
241   vlib_combined_counter_main_t *cm = &load_balance_main.lbm_to_counters;
242
243   from = vlib_frame_vector_args (from_frame);
244   n_left_from = from_frame->n_vectors;
245
246   next_index = node->cached_next_index;
247
248   while (n_left_from > 0)
249     {
250       u32 n_left_to_next;
251
252       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
253
254       while (n_left_from > 0 && n_left_to_next > 0)
255         {
256           vlib_buffer_t *b0;
257           u32 bi0, lbi0;
258           ethernet_header_t *e0;
259
260           bi0 = from[0];
261           to_next[0] = bi0;
262           from += 1;
263           to_next += 1;
264           n_left_from -= 1;
265           n_left_to_next -= 1;
266
267           b0 = vlib_get_buffer (vm, bi0);
268           e0 = vlib_buffer_get_current (b0);
269
270           vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_MAC;
271
272           /* lookup dst + src mac */
273           lbi0 = lisp_l2_fib_lookup (lgm, vnet_buffer (b0)->l2.bd_index,
274                                      e0->src_address, e0->dst_address);
275           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = lbi0;
276
277           vlib_increment_combined_counter (cm, thread_index, lbi0, 1,
278                                            vlib_buffer_length_in_chain (vm,
279                                                                         b0));
280           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
281             {
282               l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
283                                                            sizeof (*tr));
284               tr->dpo_index = lbi0;
285             }
286           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
287                                            n_left_to_next, bi0, l2_arc_to_lb);
288         }
289
290       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
291     }
292
293   return from_frame->n_vectors;
294 }
295
296 static u8 *
297 format_l2_lisp_gpe_name (u8 * s, va_list * args)
298 {
299   u32 dev_instance = va_arg (*args, u32);
300   return format (s, "l2_lisp_gpe%d", dev_instance);
301 }
302
303 /* *INDENT-OFF* */
304 VNET_DEVICE_CLASS (l2_lisp_gpe_device_class,static) = {
305   .name = "L2_LISP_GPE",
306   .format_device_name = format_l2_lisp_gpe_name,
307   .format_tx_trace = format_l2_lisp_gpe_tx_trace,
308   .tx_function = l2_lisp_gpe_interface_tx,
309 };
310 /* *INDENT-ON* */
311
312 typedef struct
313 {
314   u32 dpo_index;
315 } nsh_lisp_gpe_tx_trace_t;
316
317 u8 *
318 format_nsh_lisp_gpe_tx_trace (u8 * s, va_list * args)
319 {
320   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
321   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
322   nsh_lisp_gpe_tx_trace_t *t = va_arg (*args, nsh_lisp_gpe_tx_trace_t *);
323
324   s = format (s, "NSH-GPE-TX: tunnel %d", t->dpo_index);
325   return s;
326 }
327
328 /**
329  * @brief LISP-GPE interface TX for NSH overlays.
330  * @node nsh_lisp_gpe_interface_tx
331  *
332  * The NSH LISP-GPE interface TX function.
333  *
334  * @param[in]   vm        vlib_main_t corresponding to the current thread.
335  * @param[in]   node      vlib_node_runtime_t data for this node.
336  * @param[in]   frame     vlib_frame_t whose contents should be dispatched.
337  *
338  * @return number of vectors in frame.
339  */
340 static uword
341 nsh_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
342                            vlib_frame_t * from_frame)
343 {
344   u32 n_left_from, next_index, *from, *to_next;
345   lisp_gpe_main_t *lgm = &lisp_gpe_main;
346
347   from = vlib_frame_vector_args (from_frame);
348   n_left_from = from_frame->n_vectors;
349
350   next_index = node->cached_next_index;
351
352   while (n_left_from > 0)
353     {
354       u32 n_left_to_next;
355
356       vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
357
358       while (n_left_from > 0 && n_left_to_next > 0)
359         {
360           vlib_buffer_t *b0;
361           u32 bi0;
362           u32 *nsh0, next0;
363           const dpo_id_t *dpo0;
364
365           bi0 = from[0];
366           to_next[0] = bi0;
367           from += 1;
368           to_next += 1;
369           n_left_from -= 1;
370           n_left_to_next -= 1;
371
372           b0 = vlib_get_buffer (vm, bi0);
373           nsh0 = vlib_buffer_get_current (b0);
374
375           vnet_buffer (b0)->lisp.overlay_afi = LISP_AFI_LCAF;
376
377           /* lookup SPI + SI (second word of the NSH header).
378            * NB: Load balancing was done by the control plane */
379           dpo0 = lisp_nsh_fib_lookup (lgm, nsh0[1]);
380
381           next0 = dpo0->dpoi_next_node;
382           vnet_buffer (b0)->ip.adj_index[VLIB_TX] = dpo0->dpoi_index;
383
384           if (PREDICT_FALSE (b0->flags & VLIB_BUFFER_IS_TRACED))
385             {
386               nsh_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
387                                                             sizeof (*tr));
388               tr->dpo_index = dpo0->dpoi_index;
389             }
390           vlib_validate_buffer_enqueue_x1 (vm, node, next_index, to_next,
391                                            n_left_to_next, bi0, next0);
392         }
393
394       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
395     }
396
397   return from_frame->n_vectors;
398 }
399
400 static u8 *
401 format_nsh_lisp_gpe_name (u8 * s, va_list * args)
402 {
403   u32 dev_instance = va_arg (*args, u32);
404   return format (s, "nsh_lisp_gpe%d", dev_instance);
405 }
406
407 /* *INDENT-OFF* */
408 VNET_DEVICE_CLASS (nsh_lisp_gpe_device_class,static) = {
409   .name = "NSH_LISP_GPE",
410   .format_device_name = format_nsh_lisp_gpe_name,
411   .format_tx_trace = format_nsh_lisp_gpe_tx_trace,
412   .tx_function = nsh_lisp_gpe_interface_tx,
413 };
414 /* *INDENT-ON* */
415
416 static vnet_hw_interface_t *
417 lisp_gpe_create_iface (lisp_gpe_main_t * lgm, u32 vni, u32 dp_table,
418                        vnet_device_class_t * dev_class,
419                        tunnel_lookup_t * tuns)
420 {
421   u32 flen;
422   u32 hw_if_index = ~0;
423   u8 *new_name;
424   vnet_hw_interface_t *hi;
425   vnet_main_t *vnm = lgm->vnet_main;
426
427   /* create hw lisp_gpeX iface if needed, otherwise reuse existing */
428   flen = vec_len (lgm->free_tunnel_hw_if_indices);
429   if (flen > 0)
430     {
431       hw_if_index = lgm->free_tunnel_hw_if_indices[flen - 1];
432       _vec_len (lgm->free_tunnel_hw_if_indices) -= 1;
433
434       hi = vnet_get_hw_interface (vnm, hw_if_index);
435
436       /* rename interface */
437       new_name = format (0, "%U", dev_class->format_device_name, vni);
438
439       vec_add1 (new_name, 0);
440       vnet_rename_interface (vnm, hw_if_index, (char *) new_name);
441       vec_free (new_name);
442
443       /* clear old stats of freed interface before reuse */
444       vnet_interface_main_t *im = &vnm->interface_main;
445       vnet_interface_counter_lock (im);
446       vlib_zero_combined_counter (&im->combined_sw_if_counters
447                                   [VNET_INTERFACE_COUNTER_TX],
448                                   hi->sw_if_index);
449       vlib_zero_combined_counter (&im->combined_sw_if_counters
450                                   [VNET_INTERFACE_COUNTER_RX],
451                                   hi->sw_if_index);
452       vlib_zero_simple_counter (&im->sw_if_counters
453                                 [VNET_INTERFACE_COUNTER_DROP],
454                                 hi->sw_if_index);
455       vnet_interface_counter_unlock (im);
456     }
457   else
458     {
459       hw_if_index = vnet_register_interface (vnm, dev_class->index, vni,
460                                              lisp_gpe_hw_class.index, 0);
461       hi = vnet_get_hw_interface (vnm, hw_if_index);
462     }
463
464   hash_set (tuns->hw_if_index_by_dp_table, dp_table, hw_if_index);
465
466   /* set tunnel termination: post decap, packets are tagged as having been
467    * originated by lisp-gpe interface */
468   hash_set (tuns->sw_if_index_by_vni, vni, hi->sw_if_index);
469   hash_set (tuns->vni_by_sw_if_index, hi->sw_if_index, vni);
470
471   return hi;
472 }
473
474 static void
475 lisp_gpe_remove_iface (lisp_gpe_main_t * lgm, u32 hi_index, u32 dp_table,
476                        tunnel_lookup_t * tuns)
477 {
478   vnet_main_t *vnm = lgm->vnet_main;
479   vnet_hw_interface_t *hi;
480   uword *vnip;
481
482   hi = vnet_get_hw_interface (vnm, hi_index);
483
484   /* disable interface */
485   vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0 /* down */ );
486   vnet_hw_interface_set_flags (vnm, hi->hw_if_index, 0 /* down */ );
487   hash_unset (tuns->hw_if_index_by_dp_table, dp_table);
488   vec_add1 (lgm->free_tunnel_hw_if_indices, hi->hw_if_index);
489
490   /* clean tunnel termination and vni to sw_if_index binding */
491   vnip = hash_get (tuns->vni_by_sw_if_index, hi->sw_if_index);
492   if (0 == vnip)
493     {
494       clib_warning ("No vni associated to interface %d", hi->sw_if_index);
495       return;
496     }
497   hash_unset (tuns->sw_if_index_by_vni, vnip[0]);
498   hash_unset (tuns->vni_by_sw_if_index, hi->sw_if_index);
499 }
500
501 static void
502 lisp_gpe_iface_set_table (u32 sw_if_index, u32 table_id)
503 {
504   fib_node_index_t fib_index;
505
506   fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP4, table_id,
507                                                  FIB_SOURCE_LISP);
508   ip4_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
509   ip4_sw_interface_enable_disable (sw_if_index, 1);
510
511   fib_index = fib_table_find_or_create_and_lock (FIB_PROTOCOL_IP6, table_id,
512                                                  FIB_SOURCE_LISP);
513   ip6_main.fib_index_by_sw_if_index[sw_if_index] = fib_index;
514   ip6_sw_interface_enable_disable (sw_if_index, 1);
515 }
516
517 static void
518 lisp_gpe_tenant_del_default_routes (u32 table_id)
519 {
520   fib_protocol_t proto;
521
522   FOR_EACH_FIB_IP_PROTOCOL (proto)
523   {
524     fib_prefix_t prefix = {
525       .fp_proto = proto,
526     };
527     u32 fib_index;
528
529     fib_index = fib_table_find (prefix.fp_proto, table_id);
530     fib_table_entry_special_remove (fib_index, &prefix, FIB_SOURCE_LISP);
531     fib_table_unlock (fib_index, prefix.fp_proto, FIB_SOURCE_LISP);
532   }
533 }
534
535 static void
536 lisp_gpe_tenant_add_default_routes (u32 table_id)
537 {
538   fib_protocol_t proto;
539
540   FOR_EACH_FIB_IP_PROTOCOL (proto)
541   {
542     fib_prefix_t prefix = {
543       .fp_proto = proto,
544     };
545     u32 fib_index;
546
547     /*
548      * Add a deafult route that results in a control plane punt DPO
549      */
550     fib_index = fib_table_find_or_create_and_lock (prefix.fp_proto, table_id,
551                                                    FIB_SOURCE_LISP);
552     fib_table_entry_special_dpo_add (fib_index, &prefix, FIB_SOURCE_LISP,
553                                      FIB_ENTRY_FLAG_EXCLUSIVE,
554                                      lisp_cp_dpo_get (fib_proto_to_dpo
555                                                       (proto)));
556   }
557 }
558
559
560 /**
561  * @brief Add/del LISP-GPE L3 interface.
562  *
563  * Creates LISP-GPE interface, sets ingress arcs from lisp_gpeX_lookup,
564  * installs default routes that attract all traffic with no more specific
565  * routes to lgpe-ipx-lookup, set egress arcs to ipx-lookup, sets
566  * the interface in the right vrf and enables it.
567  *
568  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
569  * @param[in]   a       Parameters to create interface.
570  *
571  * @return number of vectors in frame.
572  */
573 u32
574 lisp_gpe_add_l3_iface (lisp_gpe_main_t * lgm, u32 vni, u32 table_id,
575                        u8 with_default_routes)
576 {
577   vnet_main_t *vnm = lgm->vnet_main;
578   tunnel_lookup_t *l3_ifaces = &lgm->l3_ifaces;
579   vnet_hw_interface_t *hi;
580   uword *hip, *si;
581
582   hip = hash_get (l3_ifaces->hw_if_index_by_dp_table, table_id);
583
584   if (hip)
585     {
586       clib_warning ("vrf %d already mapped to a vni", table_id);
587       return ~0;
588     }
589
590   si = hash_get (l3_ifaces->sw_if_index_by_vni, vni);
591
592   if (si)
593     {
594       clib_warning ("Interface for vni %d already exists", vni);
595     }
596
597   /* create lisp iface and populate tunnel tables */
598   hi = lisp_gpe_create_iface (lgm, vni, table_id,
599                               &lisp_gpe_device_class, l3_ifaces);
600
601   /* insert default routes that point to lisp-cp lookup */
602   lisp_gpe_iface_set_table (hi->sw_if_index, table_id);
603   if (with_default_routes)
604     lisp_gpe_tenant_add_default_routes (table_id);
605
606   /* enable interface */
607   vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
608                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
609   vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
610                                VNET_HW_INTERFACE_FLAG_LINK_UP);
611
612   return (hi->sw_if_index);
613 }
614
615 void
616 lisp_gpe_del_l3_iface (lisp_gpe_main_t * lgm, u32 vni, u32 table_id)
617 {
618   vnet_main_t *vnm = lgm->vnet_main;
619   tunnel_lookup_t *l3_ifaces = &lgm->l3_ifaces;
620   vnet_hw_interface_t *hi;
621   uword *hip;
622
623   hip = hash_get (l3_ifaces->hw_if_index_by_dp_table, table_id);
624
625   if (hip == 0)
626     {
627       clib_warning ("The interface for vrf %d doesn't exist", table_id);
628       return;
629     }
630
631   hi = vnet_get_hw_interface (vnm, hip[0]);
632
633   lisp_gpe_remove_iface (lgm, hip[0], table_id, &lgm->l3_ifaces);
634
635   /* unset default routes */
636   ip4_sw_interface_enable_disable (hi->sw_if_index, 0);
637   ip6_sw_interface_enable_disable (hi->sw_if_index, 0);
638   lisp_gpe_tenant_del_default_routes (table_id);
639 }
640
641 /**
642  * @brief Add/del LISP-GPE L2 interface.
643  *
644  * Creates LISP-GPE interface, sets it in L2 mode in the appropriate
645  * bridge domain, sets egress arcs and enables it.
646  *
647  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
648  * @param[in]   a       Parameters to create interface.
649  *
650  * @return number of vectors in frame.
651  */
652 u32
653 lisp_gpe_add_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id)
654 {
655   vnet_main_t *vnm = lgm->vnet_main;
656   tunnel_lookup_t *l2_ifaces = &lgm->l2_ifaces;
657   vnet_hw_interface_t *hi;
658   uword *hip, *si;
659   u16 bd_index;
660
661   if (bd_id > L2_BD_ID_MAX)
662     {
663       clib_warning ("bridge domain ID %d exceed 16M limit", bd_id);
664       return ~0;
665     }
666
667   bd_index = bd_find_or_add_bd_index (&bd_main, bd_id);
668   hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index);
669
670   if (hip)
671     {
672       clib_warning ("bridge domain %d already mapped to a vni", bd_id);
673       return ~0;
674     }
675
676   si = hash_get (l2_ifaces->sw_if_index_by_vni, vni);
677   if (si)
678     {
679       clib_warning ("Interface for vni %d already exists", vni);
680       return ~0;
681     }
682
683   /* create lisp iface and populate tunnel tables */
684   hi = lisp_gpe_create_iface (lgm, vni, bd_index,
685                               &l2_lisp_gpe_device_class, &lgm->l2_ifaces);
686
687   /* enable interface */
688   vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
689                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
690   vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
691                                VNET_HW_INTERFACE_FLAG_LINK_UP);
692
693   l2_arc_to_lb = vlib_node_add_named_next (vlib_get_main (),
694                                            hi->tx_node_index,
695                                            "l2-load-balance");
696
697   /* we're ready. add iface to l2 bridge domain */
698   set_int_l2_mode (lgm->vlib_main, vnm, MODE_L2_BRIDGE, hi->sw_if_index,
699                    bd_index, L2_BD_PORT_TYPE_NORMAL, 0, 0);
700
701   return (hi->sw_if_index);
702 }
703
704 /**
705  * @brief Add/del LISP-GPE L2 interface.
706  *
707  * Creates LISP-GPE interface, sets it in L2 mode in the appropriate
708  * bridge domain, sets egress arcs and enables it.
709  *
710  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
711  * @param[in]   a       Parameters to create interface.
712  *
713  * @return number of vectors in frame.
714  */
715 void
716 lisp_gpe_del_l2_iface (lisp_gpe_main_t * lgm, u32 vni, u32 bd_id)
717 {
718   tunnel_lookup_t *l2_ifaces = &lgm->l2_ifaces;
719   vnet_hw_interface_t *hi;
720
721   u32 bd_index = bd_find_index (&bd_main, bd_id);
722   ASSERT (bd_index != ~0);
723   uword *hip = hash_get (l2_ifaces->hw_if_index_by_dp_table, bd_index);
724
725   if (hip == 0)
726     {
727       clib_warning ("The interface for bridge domain %d doesn't exist",
728                     bd_id);
729       return;
730     }
731
732   /* Remove interface from bridge .. by enabling L3 mode */
733   hi = vnet_get_hw_interface (lgm->vnet_main, hip[0]);
734   set_int_l2_mode (lgm->vlib_main, lgm->vnet_main, MODE_L3, hi->sw_if_index,
735                    0, L2_BD_PORT_TYPE_NORMAL, 0, 0);
736   lisp_gpe_remove_iface (lgm, hip[0], bd_index, &lgm->l2_ifaces);
737 }
738
739 /**
740  * @brief Add LISP-GPE NSH interface.
741  *
742  * Creates LISP-GPE interface, sets it in L3 mode.
743  *
744  * @param[in]   lgm     Reference to @ref lisp_gpe_main_t.
745  * @param[in]   a       Parameters to create interface.
746  *
747  * @return sw_if_index.
748  */
749 u32
750 vnet_lisp_gpe_add_nsh_iface (lisp_gpe_main_t * lgm)
751 {
752   vnet_main_t *vnm = lgm->vnet_main;
753   tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces;
754   vnet_hw_interface_t *hi;
755   uword *hip, *si;
756
757   hip = hash_get (nsh_ifaces->hw_if_index_by_dp_table, 0);
758
759   if (hip)
760     {
761       clib_warning ("NSH interface 0 already exists");
762       return ~0;
763     }
764
765   si = hash_get (nsh_ifaces->sw_if_index_by_vni, 0);
766   if (si)
767     {
768       clib_warning ("NSH interface already exists");
769       return ~0;
770     }
771
772   /* create lisp iface and populate tunnel tables */
773   hi = lisp_gpe_create_iface (lgm, 0, 0,
774                               &nsh_lisp_gpe_device_class, &lgm->nsh_ifaces);
775
776   /* enable interface */
777   vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
778                                VNET_SW_INTERFACE_FLAG_ADMIN_UP);
779   vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
780                                VNET_HW_INTERFACE_FLAG_LINK_UP);
781
782   return (hi->sw_if_index);
783 }
784
785 /**
786  * @brief Del LISP-GPE NSH interface.
787  *
788  */
789 void
790 vnet_lisp_gpe_del_nsh_iface (lisp_gpe_main_t * lgm)
791 {
792   tunnel_lookup_t *nsh_ifaces = &lgm->nsh_ifaces;
793   uword *hip;
794
795   hip = hash_get (nsh_ifaces->hw_if_index_by_dp_table, 0);
796
797   if (hip == 0)
798     {
799       clib_warning ("The NSH 0 interface doesn't exist");
800       return;
801     }
802   lisp_gpe_remove_iface (lgm, hip[0], 0, &lgm->nsh_ifaces);
803 }
804
805 static clib_error_t *
806 lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
807                                    vlib_cli_command_t * cmd)
808 {
809   unformat_input_t _line_input, *line_input = &_line_input;
810   u8 is_add = 1;
811   u32 table_id, vni, bd_id;
812   u8 vni_is_set = 0, vrf_is_set = 0, bd_index_is_set = 0;
813   u8 nsh_iface = 0;
814   clib_error_t *error = NULL;
815
816   if (vnet_lisp_gpe_enable_disable_status () == 0)
817     {
818       return clib_error_return (0, "LISP is disabled");
819     }
820
821   /* Get a line of input. */
822   if (!unformat_user (input, unformat_line_input, line_input))
823     return 0;
824
825   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
826     {
827       if (unformat (line_input, "add"))
828         is_add = 1;
829       else if (unformat (line_input, "del"))
830         is_add = 0;
831       else if (unformat (line_input, "vrf %d", &table_id))
832         {
833           vrf_is_set = 1;
834         }
835       else if (unformat (line_input, "vni %d", &vni))
836         {
837           vni_is_set = 1;
838         }
839       else if (unformat (line_input, "bd %d", &bd_id))
840         {
841           bd_index_is_set = 1;
842         }
843       else if (unformat (line_input, "nsh"))
844         {
845           nsh_iface = 1;
846         }
847       else
848         {
849           error = clib_error_return (0, "parse error: '%U'",
850                                      format_unformat_error, line_input);
851           goto done;
852         }
853     }
854
855   if (nsh_iface)
856     {
857       if (is_add)
858         {
859           if (~0 == vnet_lisp_gpe_add_nsh_iface (&lisp_gpe_main))
860             {
861               error = clib_error_return (0, "NSH interface not created");
862               goto done;
863             }
864         }
865       else
866         {
867           vnet_lisp_gpe_del_nsh_iface (&lisp_gpe_main);
868         }
869       goto done;
870     }
871
872   if (vrf_is_set && bd_index_is_set)
873     {
874       error = clib_error_return
875         (0, "Cannot set both vrf and brdige domain index!");
876       goto done;
877     }
878
879   if (!vni_is_set)
880     {
881       error = clib_error_return (0, "vni must be set!");
882       goto done;
883     }
884
885   if (!vrf_is_set && !bd_index_is_set)
886     {
887       error =
888         clib_error_return (0, "vrf or bridge domain index must be set!");
889       goto done;
890     }
891
892   if (bd_index_is_set)
893     {
894       if (is_add)
895         {
896           if (~0 == lisp_gpe_tenant_l2_iface_add_or_lock (vni, bd_id))
897             {
898               error = clib_error_return (0, "L2 interface not created");
899               goto done;
900             }
901         }
902       else
903         lisp_gpe_tenant_l2_iface_unlock (vni);
904     }
905   else
906     {
907       if (is_add)
908         {
909           if (~0 == lisp_gpe_tenant_l3_iface_add_or_lock (vni, table_id, 1
910                                                           /* with_default_route */
911               ))
912             {
913               error = clib_error_return (0, "L3 interface not created");
914               goto done;
915             }
916         }
917       else
918         lisp_gpe_tenant_l3_iface_unlock (vni);
919     }
920
921 done:
922   unformat_free (line_input);
923
924   return error;
925 }
926
927 /* *INDENT-OFF* */
928 VLIB_CLI_COMMAND (add_del_lisp_gpe_iface_command, static) = {
929   .path = "gpe iface",
930   .short_help = "gpe iface add/del vni <vni> vrf <vrf>",
931   .function = lisp_gpe_add_del_iface_command_fn,
932 };
933 /* *INDENT-ON* */
934
935 /*
936  * fd.io coding-style-patch-verification: ON
937  *
938  * Local Variables:
939  * eval: (c-set-style "gnu")
940  * End:
941  */