VPP-196 LISP L2/L3 tunnel multihoming
[vpp.git] / vnet / vnet / 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 #include <vppinfra/error.h>
17 #include <vppinfra/hash.h>
18 #include <vnet/vnet.h>
19 #include <vnet/ip/ip.h>
20 #include <vnet/ip/udp.h>
21 #include <vnet/ethernet/ethernet.h>
22 #include <vnet/lisp-gpe/lisp_gpe.h>
23
24 #define foreach_lisp_gpe_tx_next        \
25   _(DROP, "error-drop")                 \
26   _(IP4_LOOKUP, "ip4-lookup")           \
27   _(IP6_LOOKUP, "ip6-lookup")
28
29 typedef enum
30 {
31 #define _(sym,str) LISP_GPE_TX_NEXT_##sym,
32   foreach_lisp_gpe_tx_next
33 #undef _
34   LISP_GPE_TX_N_NEXT,
35 } lisp_gpe_tx_next_t;
36
37 typedef struct
38 {
39   u32 tunnel_index;
40 } lisp_gpe_tx_trace_t;
41
42 u8 *
43 format_lisp_gpe_tx_trace (u8 * s, va_list * args)
44 {
45   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
46   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
47   lisp_gpe_tx_trace_t * t = va_arg (*args, lisp_gpe_tx_trace_t *);
48
49   s = format (s, "LISP-GPE-TX: tunnel %d", t->tunnel_index);
50   return s;
51 }
52
53 always_inline void
54 get_one_tunnel_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0,
55                        lisp_gpe_tunnel_t ** t0, u8 is_v4)
56 {
57   u32 adj_index0, tunnel_index0;
58   ip_adjacency_t * adj0;
59
60   /* Get adjacency and from it the tunnel_index */
61   adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
62
63   if (is_v4)
64     adj0 = ip_get_adjacency (lgm->lm4, adj_index0);
65   else
66     adj0 = ip_get_adjacency (lgm->lm6, adj_index0);
67
68   tunnel_index0 = adj0->if_address_index;
69   t0[0] = pool_elt_at_index(lgm->tunnels, tunnel_index0);
70
71   ASSERT(t0[0] != 0);
72 }
73
74 always_inline void
75 encap_one_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0,
76                   lisp_gpe_tunnel_t * t0, u32 * next0)
77 {
78   ASSERT(sizeof(ip4_udp_lisp_gpe_header_t) == 36);
79   ASSERT(sizeof(ip6_udp_lisp_gpe_header_t) == 56);
80
81   lisp_gpe_sub_tunnel_t * st0;
82   u32 * sti0;
83
84   sti0 = vec_elt_at_index(t0->sub_tunnels_lbv,
85       vnet_buffer(b0)->ip.flow_hash % t0->sub_tunnels_lbv_count);
86   st0 = vec_elt_at_index(t0->sub_tunnels, sti0[0]);
87   if (st0->is_ip4)
88     {
89       ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 36, 1);
90       next0[0] = LISP_GPE_TX_NEXT_IP4_LOOKUP;
91     }
92   else
93     {
94       ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 56, 0);
95       next0[0] = LISP_GPE_TX_NEXT_IP6_LOOKUP;
96     }
97
98   /* Reset to look up tunnel partner in the configured FIB */
99   vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
100 }
101
102 always_inline void
103 get_two_tunnels_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0,
104                         vlib_buffer_t * b1, lisp_gpe_tunnel_t ** t0,
105                         lisp_gpe_tunnel_t ** t1, u8 is_v4)
106 {
107   u32 adj_index0, adj_index1, tunnel_index0, tunnel_index1;
108   ip_adjacency_t * adj0, * adj1;
109
110   /* Get adjacency and from it the tunnel_index */
111   adj_index0 = vnet_buffer(b0)->ip.adj_index[VLIB_TX];
112   adj_index1 = vnet_buffer(b1)->ip.adj_index[VLIB_TX];
113
114   if (is_v4)
115     {
116       adj0 = ip_get_adjacency (lgm->lm4, adj_index0);
117       adj1 = ip_get_adjacency (lgm->lm4, adj_index1);
118     }
119   else
120     {
121       adj0 = ip_get_adjacency (lgm->lm6, adj_index0);
122       adj1 = ip_get_adjacency (lgm->lm6, adj_index1);
123     }
124
125   tunnel_index0 = adj0->if_address_index;
126   tunnel_index1 = adj1->if_address_index;
127
128   t0[0] = pool_elt_at_index(lgm->tunnels, tunnel_index0);
129   t1[0] = pool_elt_at_index(lgm->tunnels, tunnel_index1);
130
131   ASSERT(t0[0] != 0);
132   ASSERT(t1[0] != 0);
133 }
134
135 always_inline void
136 encap_two_inline (lisp_gpe_main_t * lgm, vlib_buffer_t * b0, vlib_buffer_t * b1,
137                   lisp_gpe_tunnel_t * t0, lisp_gpe_tunnel_t * t1, u32 * next0,
138                   u32 * next1)
139 {
140   ASSERT(sizeof(ip4_udp_lisp_gpe_header_t) == 36);
141   ASSERT(sizeof(ip6_udp_lisp_gpe_header_t) == 56);
142
143   lisp_gpe_sub_tunnel_t * st0, * st1;
144   u32 * sti0, * sti1;
145   sti0 = vec_elt_at_index(t0->sub_tunnels_lbv,
146       vnet_buffer(b0)->ip.flow_hash % t0->sub_tunnels_lbv_count);
147   sti1 = vec_elt_at_index(t1->sub_tunnels_lbv,
148       vnet_buffer(b1)->ip.flow_hash % t1->sub_tunnels_lbv_count);
149   st0 = vec_elt_at_index(t0->sub_tunnels, sti0[0]);
150   st1 = vec_elt_at_index(t1->sub_tunnels, sti1[0]);
151
152   if (PREDICT_TRUE(st0->is_ip4 == st1->is_ip4))
153     {
154       if (st0->is_ip4)
155         {
156           ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 36, 1);
157           ip_udp_encap_one (lgm->vlib_main, b1, st1->rewrite, 36, 1);
158           next0[0] = next1[0] = LISP_GPE_TX_NEXT_IP4_LOOKUP;
159         }
160       else
161         {
162           ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 56, 0);
163           ip_udp_encap_one (lgm->vlib_main, b1, st1->rewrite, 56, 0);
164           next0[0] = next1[0] = LISP_GPE_TX_NEXT_IP6_LOOKUP;
165         }
166     }
167   else
168     {
169       if (st0->is_ip4)
170         {
171           ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 36, 1);
172           ip_udp_encap_one (lgm->vlib_main, b1, st1->rewrite, 56, 1);
173           next0[0] = LISP_GPE_TX_NEXT_IP4_LOOKUP;
174           next1[0] = LISP_GPE_TX_NEXT_IP6_LOOKUP;
175         }
176       else
177         {
178           ip_udp_encap_one (lgm->vlib_main, b0, st0->rewrite, 56, 1);
179           ip_udp_encap_one (lgm->vlib_main, b1, st1->rewrite, 36, 1);
180           next0[0] = LISP_GPE_TX_NEXT_IP6_LOOKUP;
181           next1[0] = LISP_GPE_TX_NEXT_IP4_LOOKUP;
182         }
183     }
184
185   /* Reset to look up tunnel partner in the configured FIB */
186   vnet_buffer(b0)->sw_if_index[VLIB_TX] = t0->encap_fib_index;
187   vnet_buffer(b1)->sw_if_index[VLIB_TX] = t1->encap_fib_index;
188 }
189
190 #define is_v4_packet(_h) ((*(u8*) _h) & 0xF0) == 0x40
191
192 static uword
193 lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
194                        vlib_frame_t * from_frame)
195 {
196   u32 n_left_from, next_index, * from, * to_next;
197   lisp_gpe_main_t * lgm = &lisp_gpe_main;
198
199   from = vlib_frame_vector_args (from_frame);
200   n_left_from = from_frame->n_vectors;
201
202   next_index = node->cached_next_index;
203
204   while (n_left_from > 0)
205     {
206       u32 n_left_to_next;
207
208       vlib_get_next_frame (vm, node, next_index,
209                            to_next, n_left_to_next);
210
211       while (n_left_from >= 4 && n_left_to_next >= 2)
212         {
213           u32 bi0, bi1;
214           vlib_buffer_t * b0, * b1;
215           u32 next0, next1;
216           lisp_gpe_tunnel_t * t0 = 0, * t1 = 0;
217           u8 is_v4_eid0, is_v4_eid1;
218
219           next0 = next1 = LISP_GPE_TX_NEXT_IP4_LOOKUP;
220
221           /* Prefetch next iteration. */
222             {
223               vlib_buffer_t * p2, *p3;
224
225               p2 = vlib_get_buffer (vm, from[2]);
226               p3 = vlib_get_buffer (vm, from[3]);
227
228               vlib_prefetch_buffer_header(p2, LOAD);
229               vlib_prefetch_buffer_header(p3, LOAD);
230
231               CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
232               CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
233             }
234
235           bi0 = from[0];
236           bi1 = from[1];
237           to_next[0] = bi0;
238           to_next[1] = bi1;
239           from += 2;
240           to_next += 2;
241           n_left_to_next -= 2;
242           n_left_from -= 2;
243
244           b0 = vlib_get_buffer (vm, bi0);
245           b1 = vlib_get_buffer (vm, bi1);
246
247           is_v4_eid0 = is_v4_packet(vlib_buffer_get_current (b0));
248           is_v4_eid1 = is_v4_packet(vlib_buffer_get_current (b1));
249
250           if (PREDICT_TRUE(is_v4_eid0 == is_v4_eid1))
251             {
252               get_two_tunnels_inline (lgm, b0, b1, &t0, &t1,
253                                       is_v4_eid0 ? 1 : 0);
254             }
255           else
256             {
257               get_one_tunnel_inline (lgm, b0, &t0, is_v4_eid0 ? 1 : 0);
258               get_one_tunnel_inline (lgm, b1, &t1, is_v4_eid1 ? 1 : 0);
259             }
260
261           encap_two_inline (lgm, b0, b1, t0, t1, &next0, &next1);
262
263           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
264             {
265               lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
266                                                            sizeof(*tr));
267               tr->tunnel_index = t0 - lgm->tunnels;
268             }
269           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
270             {
271               lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b1,
272                                                            sizeof(*tr));
273               tr->tunnel_index = t1 - lgm->tunnels;
274             }
275
276           vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
277                                           n_left_to_next, bi0, bi1, next0,
278                                           next1);
279         }
280
281       while (n_left_from > 0 && n_left_to_next > 0)
282         {
283           vlib_buffer_t * b0;
284           u32 bi0, next0 = LISP_GPE_TX_NEXT_IP4_LOOKUP;
285           lisp_gpe_tunnel_t * t0 = 0;
286           u8 is_v4_0;
287
288           bi0 = from[0];
289           to_next[0] = bi0;
290           from += 1;
291           to_next += 1;
292           n_left_from -= 1;
293           n_left_to_next -= 1;
294
295           b0 = vlib_get_buffer (vm, bi0);
296
297           is_v4_0 = is_v4_packet(vlib_buffer_get_current (b0));
298           get_one_tunnel_inline (lgm, b0, &t0, is_v4_0 ? 1 : 0);
299
300           encap_one_inline (lgm, b0, t0, &next0);
301
302           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED)) 
303             {
304               lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
305                                                            sizeof(*tr));
306               tr->tunnel_index = t0 - lgm->tunnels;
307             }
308           vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
309                                           n_left_to_next, bi0, next0);
310         }
311
312       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
313     }
314
315   return from_frame->n_vectors;
316 }
317
318 static u8 *
319 format_lisp_gpe_name (u8 * s, va_list * args)
320 {
321   u32 dev_instance = va_arg (*args, u32);
322   return format (s, "lisp_gpe%d", dev_instance);
323 }
324
325 VNET_DEVICE_CLASS (lisp_gpe_device_class,static) = {
326   .name = "LISP_GPE",
327   .format_device_name = format_lisp_gpe_name,
328   .format_tx_trace = format_lisp_gpe_tx_trace,
329   .tx_function = lisp_gpe_interface_tx,
330   .no_flatten_output_chains = 1,
331 };
332
333 static uword
334 dummy_set_rewrite (vnet_main_t * vnm, u32 sw_if_index, u32 l3_type,
335                    void * dst_address, void * rewrite, uword max_rewrite_bytes)
336 {
337   return 0;
338 }
339
340 u8 *
341 format_lisp_gpe_header_with_length (u8 * s, va_list * args)
342 {
343   lisp_gpe_header_t * h = va_arg (*args, lisp_gpe_header_t *);
344   u32 max_header_bytes = va_arg (*args, u32);
345   u32 header_bytes;
346
347   header_bytes = sizeof (h[0]);
348   if (max_header_bytes != 0 && header_bytes > max_header_bytes)
349     return format (s, "lisp-gpe header truncated");
350
351   s = format (s, "flags: ");
352 #define _(n,v) if (h->flags & v) s = format (s, "%s ", #n);
353   foreach_lisp_gpe_flag_bit;
354 #undef _
355
356   s = format (s, "\n  ver_res %d res %d next_protocol %d iid %d(%x)",
357               h->ver_res, h->res, h->next_protocol,
358               clib_net_to_host_u32 (h->iid),
359               clib_net_to_host_u32 (h->iid));
360   return s;
361 }
362
363 VNET_HW_INTERFACE_CLASS (lisp_gpe_hw_class) = {
364   .name = "LISP_GPE",
365   .format_header = format_lisp_gpe_header_with_length,
366   .set_rewrite = dummy_set_rewrite,
367 };
368
369 int
370 add_del_ip_prefix_route (ip_prefix_t * dst_prefix, u32 table_id,
371                          ip_adjacency_t * add_adj, u8 is_add, u32 * adj_index)
372 {
373   uword * p;
374
375   if (ip_prefix_version(dst_prefix) == IP4)
376     {
377       ip4_main_t * im4 = &ip4_main;
378       ip4_add_del_route_args_t a;
379       ip4_address_t addr = ip_prefix_v4(dst_prefix);
380
381       memset(&a, 0, sizeof(a));
382       a.flags = IP4_ROUTE_FLAG_TABLE_ID;
383       a.table_index_or_table_id = table_id;
384       a.adj_index = ~0;
385       a.dst_address_length = ip_prefix_len(dst_prefix);
386       a.dst_address = addr;
387       a.flags |= is_add ? IP4_ROUTE_FLAG_ADD : IP4_ROUTE_FLAG_DEL;
388       a.add_adj = add_adj;
389       a.n_add_adj = is_add ? 1 : 0;
390
391       ip4_add_del_route (im4, &a);
392
393       if (is_add)
394         {
395           p = ip4_get_route (im4, table_id, 0, addr.as_u8,
396                              ip_prefix_len(dst_prefix));
397           if (p == 0)
398             {
399               clib_warning("Failed to insert route for eid %U!",
400                            format_ip4_address_and_length, addr.as_u8,
401                            ip_prefix_len(dst_prefix));
402               return -1;
403             }
404           adj_index[0] = p[0];
405         }
406     }
407   else
408     {
409       ip6_main_t * im6 = &ip6_main;
410       ip6_add_del_route_args_t a;
411       ip6_address_t addr = ip_prefix_v6(dst_prefix);
412
413       memset(&a, 0, sizeof(a));
414       a.flags = IP6_ROUTE_FLAG_TABLE_ID;
415       a.table_index_or_table_id = table_id;
416       a.adj_index = ~0;
417       a.dst_address_length = ip_prefix_len(dst_prefix);
418       a.dst_address = addr;
419       a.flags |= is_add ? IP6_ROUTE_FLAG_ADD : IP6_ROUTE_FLAG_DEL;
420       a.add_adj = add_adj;
421       a.n_add_adj = is_add ? 1 : 0;
422
423       ip6_add_del_route (im6, &a);
424
425       if (is_add)
426         {
427           adj_index[0] = ip6_get_route (im6, table_id, 0, &addr,
428                                         ip_prefix_len(dst_prefix));
429           if (adj_index[0] == 0)
430             {
431               clib_warning("Failed to insert route for eid %U!",
432                            format_ip6_address_and_length, addr.as_u8,
433                            ip_prefix_len(dst_prefix));
434               return -1;
435             }
436         }
437     }
438   return 0;
439 }
440
441 static void
442 add_del_lisp_gpe_default_route (u32 table_id, u8 is_v4, u8 is_add)
443 {
444   lisp_gpe_main_t * lgm = &lisp_gpe_main;
445   ip_adjacency_t adj;
446   ip_prefix_t prefix;
447   u32 adj_index = 0;
448
449   /* setup adjacency */
450   memset (&adj, 0, sizeof(adj));
451
452   adj.n_adj = 1;
453   adj.explicit_fib_index = ~0;
454   adj.lookup_next_index = is_v4 ? lgm->ip4_lookup_next_lgpe_ip4_lookup :
455                                   lgm->ip6_lookup_next_lgpe_ip6_lookup;
456   /* default route has tunnel_index ~0 */
457   adj.rewrite_header.sw_if_index = ~0;
458
459   /* set prefix to 0/0 */
460   memset(&prefix, 0, sizeof(prefix));
461   ip_prefix_version(&prefix) = is_v4 ? IP4 : IP6;
462
463   /* add/delete route for prefix */
464   add_del_ip_prefix_route (&prefix, table_id, &adj, is_add, &adj_index);
465 }
466
467 static void
468 lisp_gpe_iface_set_table (u32 sw_if_index, u32 table_id, u8 is_ip4)
469 {
470   if (is_ip4)
471     {
472       ip4_main_t * im4 = &ip4_main;
473       ip4_fib_t * fib;
474       fib = find_ip4_fib_by_table_index_or_id (im4, table_id,
475                                                IP4_ROUTE_FLAG_TABLE_ID);
476
477       /* fib's created if it doesn't exist */
478       ASSERT(fib != 0);
479
480       vec_validate(im4->fib_index_by_sw_if_index, sw_if_index);
481       im4->fib_index_by_sw_if_index[sw_if_index] = fib->index;
482     }
483   else
484     {
485       ip6_main_t * im6 = &ip6_main;
486       ip6_fib_t * fib;
487       fib = find_ip6_fib_by_table_index_or_id (im6, table_id,
488                                                IP6_ROUTE_FLAG_TABLE_ID);
489
490       /* fib's created if it doesn't exist */
491       ASSERT(fib != 0);
492
493       vec_validate(im6->fib_index_by_sw_if_index, sw_if_index);
494       im6->fib_index_by_sw_if_index[sw_if_index] = fib->index;
495     }
496 }
497
498 #define foreach_l2_lisp_gpe_tx_next     \
499   _(DROP, "error-drop")                 \
500   _(IP4_LOOKUP, "ip4-lookup")           \
501   _(IP6_LOOKUP, "ip6-lookup")           \
502   _(LISP_CP_LOOKUP, "lisp-cp-lookup")
503
504 typedef enum
505 {
506 #define _(sym,str) L2_LISP_GPE_TX_NEXT_##sym,
507   foreach_l2_lisp_gpe_tx_next
508 #undef _
509   L2_LISP_GPE_TX_N_NEXT,
510 } l2_lisp_gpe_tx_next_t;
511
512 typedef struct
513 {
514   u32 tunnel_index;
515 } l2_lisp_gpe_tx_trace_t;
516
517 u8 *
518 format_l2_lisp_gpe_tx_trace (u8 * s, va_list * args)
519 {
520   CLIB_UNUSED (vlib_main_t * vm) = va_arg (*args, vlib_main_t *);
521   CLIB_UNUSED (vlib_node_t * node) = va_arg (*args, vlib_node_t *);
522   l2_lisp_gpe_tx_trace_t * t = va_arg (*args, l2_lisp_gpe_tx_trace_t *);
523
524   s = format (s, "L2-LISP-GPE-TX: tunnel %d", t->tunnel_index);
525   return s;
526 }
527
528 always_inline void
529 l2_process_tunnel_action (vlib_buffer_t * b0, u8 action, u32 * next0)
530 {
531   if (LISP_SEND_MAP_REQUEST == action)
532     {
533       next0[0] = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
534       vnet_buffer(b0)->lisp.overlay_afi = LISP_AFI_MAC;
535     }
536   else
537     {
538       next0[0] = L2_LISP_GPE_TX_NEXT_DROP;
539     }
540 }
541
542 always_inline u32
543 ip_flow_hash (void * data)
544 {
545   ip4_header_t * iph = (ip4_header_t *) data;
546
547   if ((iph->ip_version_and_header_length & 0xF0) == 0x40)
548     return ip4_compute_flow_hash (iph, IP_FLOW_HASH_DEFAULT);
549   else
550     return ip6_compute_flow_hash ((ip6_header_t *) iph, IP_FLOW_HASH_DEFAULT);
551 }
552
553 always_inline u32
554 l2_flow_hash (vlib_buffer_t * b0)
555 {
556   ethernet_header_t * eh;
557   u64 a, b, c;
558   uword is_ip, eh_size;
559   u16 eh_type;
560
561   eh = vlib_buffer_get_current (b0);
562   eh_type = clib_net_to_host_u16(eh->type);
563   eh_size = ethernet_buffer_header_size(b0);
564
565   is_ip = (eh_type == ETHERNET_TYPE_IP4 || eh_type == ETHERNET_TYPE_IP6);
566
567   /* since we have 2 cache lines, use them */
568   if (is_ip)
569     a = ip_flow_hash ((u8 *) vlib_buffer_get_current (b0) + eh_size);
570   else
571     a = eh->type;
572
573   b = mac_to_u64((u8 *)eh->dst_address);
574   c = mac_to_u64((u8 *)eh->src_address);
575   hash_mix64 (a, b, c);
576
577   return (u32) c;
578 }
579
580 always_inline void
581 l2_process_one (lisp_gpe_main_t * lgm, vlib_buffer_t * b0, u32 ti0, u32 * next0)
582 {
583   lisp_gpe_tunnel_t * t0;
584
585   t0 = pool_elt_at_index(lgm->tunnels, ti0);
586   ASSERT(0 != t0);
587
588   if (PREDICT_TRUE(LISP_NO_ACTION == t0->action))
589     {
590       /* compute 'flow' hash */
591       if (PREDICT_TRUE(t0->sub_tunnels_lbv_count > 1))
592         vnet_buffer(b0)->ip.flow_hash = l2_flow_hash (b0);
593       encap_one_inline (lgm, b0, t0, next0);
594     }
595   else
596     {
597       l2_process_tunnel_action(b0, t0->action, next0);
598     }
599 }
600
601 always_inline void
602 l2_process_two (lisp_gpe_main_t * lgm, vlib_buffer_t * b0, vlib_buffer_t * b1,
603                 u32 ti0, u32 ti1, u32 * next0, u32 * next1)
604 {
605   lisp_gpe_tunnel_t * t0, * t1;
606
607   t0 = pool_elt_at_index(lgm->tunnels, ti0);
608   t1 = pool_elt_at_index(lgm->tunnels, ti1);
609
610   ASSERT(0 != t0 && 0 != t1);
611
612   if (PREDICT_TRUE(LISP_NO_ACTION == t0->action
613                    && LISP_NO_ACTION == t1->action))
614     {
615       if (PREDICT_TRUE(t0->sub_tunnels_lbv_count > 1))
616         vnet_buffer(b0)->ip.flow_hash = l2_flow_hash(b0);
617       if (PREDICT_TRUE(t1->sub_tunnels_lbv_count > 1))
618         vnet_buffer(b1)->ip.flow_hash = l2_flow_hash(b1);
619       encap_two_inline (lgm, b0, b1, t0, t1, next0, next1);
620     }
621   else
622     {
623       if (LISP_NO_ACTION == t0->action)
624         {
625           if (PREDICT_TRUE(t0->sub_tunnels_lbv_count > 1))
626             vnet_buffer(b0)->ip.flow_hash = l2_flow_hash(b0);
627           encap_one_inline (lgm, b0, t0, next0);
628           l2_process_tunnel_action (b1, t1->action, next1);
629         }
630       else if (LISP_NO_ACTION == t1->action)
631         {
632           if (PREDICT_TRUE(t1->sub_tunnels_lbv_count > 1))
633             vnet_buffer(b1)->ip.flow_hash = l2_flow_hash(b1);
634           encap_one_inline (lgm, b1, t1, next1);
635           l2_process_tunnel_action (b0, t0->action, next0);
636         }
637       else
638         {
639           l2_process_tunnel_action (b0, t0->action, next0);
640           l2_process_tunnel_action (b1, t1->action, next1);
641         }
642     }
643 }
644
645 static uword
646 l2_lisp_gpe_interface_tx (vlib_main_t * vm, vlib_node_runtime_t * node,
647                           vlib_frame_t * from_frame)
648 {
649   u32 n_left_from, next_index, * from, * to_next;
650   lisp_gpe_main_t * lgm = &lisp_gpe_main;
651
652   from = vlib_frame_vector_args (from_frame);
653   n_left_from = from_frame->n_vectors;
654
655   next_index = node->cached_next_index;
656
657   while (n_left_from > 0)
658     {
659       u32 n_left_to_next;
660
661       vlib_get_next_frame (vm, node, next_index,
662                            to_next, n_left_to_next);
663
664       while (n_left_from >= 4 && n_left_to_next >= 2)
665         {
666           u32 bi0, bi1;
667           vlib_buffer_t * b0, * b1;
668           u32 next0, next1, ti0, ti1;
669           lisp_gpe_tunnel_t * t0 = 0, * t1 = 0;
670           ethernet_header_t * e0, * e1;
671
672           next0 = next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
673
674           /* Prefetch next iteration. */
675             {
676               vlib_buffer_t * p2, *p3;
677
678               p2 = vlib_get_buffer (vm, from[2]);
679               p3 = vlib_get_buffer (vm, from[3]);
680
681               vlib_prefetch_buffer_header(p2, LOAD);
682               vlib_prefetch_buffer_header(p3, LOAD);
683
684               CLIB_PREFETCH(p2->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
685               CLIB_PREFETCH(p3->data, 2*CLIB_CACHE_LINE_BYTES, LOAD);
686             }
687
688           bi0 = from[0];
689           bi1 = from[1];
690           to_next[0] = bi0;
691           to_next[1] = bi1;
692           from += 2;
693           to_next += 2;
694           n_left_to_next -= 2;
695           n_left_from -= 2;
696
697           b0 = vlib_get_buffer (vm, bi0);
698           b1 = vlib_get_buffer (vm, bi1);
699
700           e0 = vlib_buffer_get_current (b0);
701           e1 = vlib_buffer_get_current (b1);
702
703           /* lookup dst + src mac */
704           ti0 = lisp_l2_fib_lookup (lgm, vnet_buffer(b0)->l2.bd_index,
705                                     e0->src_address, e0->dst_address);
706           ti1 = lisp_l2_fib_lookup (lgm, vnet_buffer(b1)->l2.bd_index,
707                                     e1->src_address, e1->dst_address);
708
709           if (PREDICT_TRUE((u32)~0 != ti0) && (u32)~0 != ti1)
710             {
711               /* process both tunnels */
712               l2_process_two (lgm, b0, b1, ti0, ti1, &next0, &next1);
713             }
714           else
715             {
716               if ((u32)~0 != ti0)
717                 {
718                   /* process tunnel for b0 */
719                   l2_process_one (lgm, b0, ti0, &next0);
720
721                   /* no tunnel found for b1, send to control plane */
722                   next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
723                   vnet_buffer(b1)->lisp.overlay_afi = LISP_AFI_MAC;
724                 }
725               else if ((u32)~0 != ti1)
726                 {
727                   /* process tunnel for b1 */
728                   l2_process_one (lgm, b1, ti1, &next1);
729
730                   /* no tunnel found b0, send to control plane */
731                   next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
732                   vnet_buffer(b0)->lisp.overlay_afi = LISP_AFI_MAC;
733                 }
734               else
735                 {
736                   /* no tunnels found */
737                   next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
738                   vnet_buffer(b0)->lisp.overlay_afi = LISP_AFI_MAC;
739                   next1 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
740                   vnet_buffer(b1)->lisp.overlay_afi = LISP_AFI_MAC;
741                 }
742             }
743
744           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
745             {
746               l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
747                                                            sizeof(*tr));
748               tr->tunnel_index = t0 - lgm->tunnels;
749             }
750           if (PREDICT_FALSE(b1->flags & VLIB_BUFFER_IS_TRACED))
751             {
752               l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b1,
753                                                            sizeof(*tr));
754               tr->tunnel_index = t1 - lgm->tunnels;
755             }
756
757           vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next,
758                                           n_left_to_next, bi0, bi1, next0,
759                                           next1);
760         }
761
762       while (n_left_from > 0 && n_left_to_next > 0)
763         {
764           vlib_buffer_t * b0;
765           u32 bi0, ti0, next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
766           ethernet_header_t * e0;
767
768           bi0 = from[0];
769           to_next[0] = bi0;
770           from += 1;
771           to_next += 1;
772           n_left_from -= 1;
773           n_left_to_next -= 1;
774
775           b0 = vlib_get_buffer (vm, bi0);
776           e0 = vlib_buffer_get_current (b0);
777
778           /* lookup dst + src mac */
779           ti0 = lisp_l2_fib_lookup (lgm, vnet_buffer(b0)->l2.bd_index,
780                                     e0->src_address, e0->dst_address);
781
782           if (PREDICT_TRUE((u32)~0 != ti0))
783             {
784               l2_process_one (lgm, b0, ti0, &next0);
785             }
786           else
787             {
788               /* no tunnel found send to control plane */
789               next0 = L2_LISP_GPE_TX_NEXT_LISP_CP_LOOKUP;
790               vnet_buffer(b0)->lisp.overlay_afi = LISP_AFI_MAC;
791             }
792
793           if (PREDICT_FALSE(b0->flags & VLIB_BUFFER_IS_TRACED))
794             {
795               l2_lisp_gpe_tx_trace_t *tr = vlib_add_trace (vm, node, b0,
796                                                            sizeof(*tr));
797               tr->tunnel_index = ti0 ? ti0 : ~0;
798             }
799           vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next,
800                                           n_left_to_next, bi0, next0);
801         }
802
803       vlib_put_next_frame (vm, node, next_index, n_left_to_next);
804     }
805
806   return from_frame->n_vectors;
807 }
808
809 static u8 *
810 format_l2_lisp_gpe_name (u8 * s, va_list * args)
811 {
812   u32 dev_instance = va_arg (*args, u32);
813   return format (s, "l2_lisp_gpe%d", dev_instance);
814 }
815
816 VNET_DEVICE_CLASS (l2_lisp_gpe_device_class,static) = {
817   .name = "L2_LISP_GPE",
818   .format_device_name = format_l2_lisp_gpe_name,
819   .format_tx_trace = format_lisp_gpe_tx_trace,
820   .tx_function = l2_lisp_gpe_interface_tx,
821   .no_flatten_output_chains = 1,
822 };
823
824
825 static vnet_hw_interface_t *
826 create_lisp_gpe_iface (lisp_gpe_main_t * lgm, u32 vni, u32 dp_table,
827                        vnet_device_class_t * dev_class,
828                        tunnel_lookup_t * tuns)
829 {
830   u32 flen;
831   u32 hw_if_index = ~0;
832   u8 * new_name;
833   vnet_hw_interface_t * hi;
834   vnet_main_t * vnm = lgm->vnet_main;
835
836   /* create hw lisp_gpeX iface if needed, otherwise reuse existing */
837   flen = vec_len(lgm->free_tunnel_hw_if_indices);
838   if (flen > 0)
839     {
840       hw_if_index = lgm->free_tunnel_hw_if_indices[flen - 1];
841       _vec_len(lgm->free_tunnel_hw_if_indices) -= 1;
842
843       hi = vnet_get_hw_interface (vnm, hw_if_index);
844
845       /* rename interface */
846       new_name = format (0, "%U", dev_class->format_device_name,
847                          vni);
848
849       vec_add1(new_name, 0);
850       vnet_rename_interface (vnm, hw_if_index, (char *) new_name);
851       vec_free(new_name);
852
853       /* clear old stats of freed interface before reuse */
854       vnet_interface_main_t * im = &vnm->interface_main;
855       vnet_interface_counter_lock (im);
856       vlib_zero_combined_counter (
857           &im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_TX],
858           hi->sw_if_index);
859       vlib_zero_combined_counter (
860           &im->combined_sw_if_counters[VNET_INTERFACE_COUNTER_RX],
861           hi->sw_if_index);
862       vlib_zero_simple_counter (
863           &im->sw_if_counters[VNET_INTERFACE_COUNTER_DROP],
864           hi->sw_if_index);
865       vnet_interface_counter_unlock (im);
866     }
867   else
868     {
869       hw_if_index = vnet_register_interface (vnm, dev_class->index, vni,
870                                              lisp_gpe_hw_class.index, 0);
871       hi = vnet_get_hw_interface (vnm, hw_if_index);
872     }
873
874   hash_set(tuns->hw_if_index_by_dp_table, dp_table, hw_if_index);
875
876   /* set tunnel termination: post decap, packets are tagged as having been
877    * originated by lisp-gpe interface */
878   hash_set(tuns->sw_if_index_by_vni, vni, hi->sw_if_index);
879   hash_set(tuns->vni_by_sw_if_index, hi->sw_if_index, vni);
880
881   return hi;
882 }
883
884 static void
885 remove_lisp_gpe_iface (lisp_gpe_main_t * lgm, u32 hi_index, u32 dp_table,
886                        tunnel_lookup_t * tuns)
887 {
888   vnet_main_t * vnm = lgm->vnet_main;
889   vnet_hw_interface_t * hi;
890   uword * vnip;
891
892   hi = vnet_get_hw_interface (vnm, hi_index);
893
894   /* disable interface */
895   vnet_sw_interface_set_flags (vnm, hi->sw_if_index, 0/* down */);
896   vnet_hw_interface_set_flags (vnm, hi->hw_if_index, 0/* down */);
897   hash_unset(tuns->hw_if_index_by_dp_table, dp_table);
898   vec_add1(lgm->free_tunnel_hw_if_indices, hi->hw_if_index);
899
900   /* clean tunnel termination and vni to sw_if_index binding */
901   vnip = hash_get(tuns->vni_by_sw_if_index, hi->sw_if_index);
902   if (0 == vnip)
903     {
904       clib_warning ("No vni associated to interface %d", hi->sw_if_index);
905       return;
906     }
907   hash_unset(tuns->sw_if_index_by_vni, vnip[0]);
908   hash_unset(tuns->vni_by_sw_if_index, hi->sw_if_index);
909 }
910
911 static int
912 lisp_gpe_add_del_l3_iface (lisp_gpe_main_t * lgm,
913                            vnet_lisp_gpe_add_del_iface_args_t * a)
914 {
915   vnet_main_t * vnm = lgm->vnet_main;
916   tunnel_lookup_t * l3_ifaces = &lgm->l3_ifaces;
917   vnet_hw_interface_t * hi;
918   u32 lookup_next_index4, lookup_next_index6;
919   uword * hip, * si;
920
921   hip = hash_get(l3_ifaces->hw_if_index_by_dp_table, a->table_id);
922
923   if (a->is_add)
924     {
925       if (hip)
926         {
927           clib_warning ("vrf %d already mapped to a vni", a->table_id);
928           return -1;
929         }
930
931       si = hash_get(l3_ifaces->sw_if_index_by_vni, a->vni);
932       if (si)
933         {
934           clib_warning ("Interface for vni %d already exists", a->vni);
935           return -1;
936         }
937
938       /* create lisp iface and populate tunnel tables */
939       hi = create_lisp_gpe_iface (lgm, a->vni, a->table_id,
940                                   &lisp_gpe_device_class, l3_ifaces);
941
942       /* set ingress arc from lgpe_ipX_lookup */
943       lookup_next_index4 = vlib_node_add_next (lgm->vlib_main,
944                                                lgpe_ip4_lookup_node.index,
945                                                hi->output_node_index);
946       lookup_next_index6 = vlib_node_add_next (lgm->vlib_main,
947                                                lgpe_ip6_lookup_node.index,
948                                                hi->output_node_index);
949       hash_set(lgm->lgpe_ip4_lookup_next_index_by_table_id, a->table_id,
950                lookup_next_index4);
951       hash_set(lgm->lgpe_ip6_lookup_next_index_by_table_id, a->table_id,
952                lookup_next_index6);
953
954       /* insert default routes that point to lgpe-ipx-lookup */
955       add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */1, 1);
956       add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */0, 1);
957
958       /* set egress arcs */
959 #define _(sym,str) vlib_node_add_named_next_with_slot (vnm->vlib_main, \
960                     hi->tx_node_index, str, LISP_GPE_TX_NEXT_##sym);
961           foreach_lisp_gpe_tx_next
962 #undef _
963
964       /* set interface in appropriate v4 and v6 FIBs */
965       lisp_gpe_iface_set_table (hi->sw_if_index, a->table_id, 1);
966       lisp_gpe_iface_set_table (hi->sw_if_index, a->table_id, 0);
967
968       /* enable interface */
969       vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
970                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
971       vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
972                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
973     }
974   else
975     {
976       if (hip == 0)
977         {
978           clib_warning("The interface for vrf %d doesn't exist", a->table_id);
979           return -1;
980         }
981
982       remove_lisp_gpe_iface (lgm, hip[0], a->table_id, &lgm->l3_ifaces);
983
984       /* unset default routes */
985       add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */1, 0);
986       add_del_lisp_gpe_default_route (a->table_id, /* is_v4 */0, 0);
987     }
988
989   return 0;
990 }
991
992 static int
993 lisp_gpe_add_del_l2_iface (lisp_gpe_main_t * lgm,
994                            vnet_lisp_gpe_add_del_iface_args_t * a)
995 {
996   vnet_main_t * vnm = lgm->vnet_main;
997   tunnel_lookup_t * l2_ifaces = &lgm->l2_ifaces;
998   vnet_hw_interface_t * hi;
999   uword * hip, * si;
1000   u16 bd_index;
1001
1002   bd_index = bd_find_or_add_bd_index(&bd_main, a->bd_id);
1003   hip = hash_get(l2_ifaces->hw_if_index_by_dp_table, bd_index);
1004
1005   if (a->is_add)
1006     {
1007       if (hip)
1008         {
1009           clib_warning("bridge domain %d already mapped to a vni", a->bd_id);
1010           return -1;
1011         }
1012
1013       si = hash_get(l2_ifaces->sw_if_index_by_vni, a->vni);
1014       if (si)
1015         {
1016           clib_warning ("Interface for vni %d already exists", a->vni);
1017           return -1;
1018         }
1019
1020       /* create lisp iface and populate tunnel tables */
1021       hi = create_lisp_gpe_iface (lgm, a->vni, bd_index,
1022                                   &l2_lisp_gpe_device_class, &lgm->l2_ifaces);
1023
1024       /* add iface to l2 bridge domain */
1025       set_int_l2_mode (lgm->vlib_main, vnm, MODE_L2_BRIDGE, hi->sw_if_index,
1026                        bd_index, 0, 0, 0);
1027
1028       /* set egress arcs */
1029 #define _(sym,str) vlib_node_add_named_next_with_slot (vnm->vlib_main, \
1030                     hi->tx_node_index, str, L2_LISP_GPE_TX_NEXT_##sym);
1031           foreach_l2_lisp_gpe_tx_next
1032 #undef _
1033
1034       /* enable interface */
1035       vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1036                                    VNET_SW_INTERFACE_FLAG_ADMIN_UP);
1037       vnet_hw_interface_set_flags (vnm, hi->hw_if_index,
1038                                    VNET_HW_INTERFACE_FLAG_LINK_UP);
1039     }
1040   else
1041     {
1042       if (hip == 0)
1043         {
1044           clib_warning("The interface for bridge domain %d doesn't exist",
1045                        a->bd_id);
1046           return -1;
1047         }
1048       remove_lisp_gpe_iface (lgm, hip[0], bd_index, &lgm->l2_ifaces);
1049     }
1050
1051   return 0;
1052 }
1053
1054 int
1055 vnet_lisp_gpe_add_del_iface (vnet_lisp_gpe_add_del_iface_args_t * a,
1056                              u32 * hw_if_indexp)
1057 {
1058   lisp_gpe_main_t * lgm = &lisp_gpe_main;
1059
1060   if (vnet_lisp_gpe_enable_disable_status() == 0)
1061     {
1062       clib_warning ("LISP is disabled!");
1063       return VNET_API_ERROR_LISP_DISABLED;
1064     }
1065
1066   if (!a->is_l2)
1067     return lisp_gpe_add_del_l3_iface (lgm, a);
1068   else
1069     return lisp_gpe_add_del_l2_iface (lgm, a);
1070 }
1071
1072 static clib_error_t *
1073 lisp_gpe_add_del_iface_command_fn (vlib_main_t * vm, unformat_input_t * input,
1074                                    vlib_cli_command_t * cmd)
1075 {
1076   unformat_input_t _line_input, * line_input = &_line_input;
1077   u8 is_add = 1;
1078   clib_error_t * error = 0;
1079   int rv = 0;
1080   u32 table_id, vni, bd_id;
1081   u8 vni_is_set = 0, vrf_is_set = 0, bd_index_is_set = 0;
1082
1083   vnet_lisp_gpe_add_del_iface_args_t _a, * a = &_a;
1084
1085   /* Get a line of input. */
1086   if (! unformat_user (input, unformat_line_input, line_input))
1087     return 0;
1088
1089   while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1090     {
1091       if (unformat (line_input, "add"))
1092         is_add = 1;
1093       else if (unformat (line_input, "del"))
1094         is_add = 0;
1095       else if (unformat (line_input, "vrf %d", &table_id))
1096         {
1097           vrf_is_set = 1;
1098         }
1099       else if (unformat (line_input, "vni %d", &vni))
1100         {
1101           vni_is_set = 1;
1102         }
1103       else if (unformat (line_input, "bd %d", &bd_id))
1104         {
1105           bd_index_is_set = 1;
1106         }
1107       else
1108         {
1109           return clib_error_return (0, "parse error: '%U'",
1110                                    format_unformat_error, line_input);
1111         }
1112     }
1113
1114   if (vrf_is_set && bd_index_is_set)
1115     return clib_error_return(0, "Cannot set both vrf and brdige domain index!");
1116
1117   if (!vni_is_set)
1118     return clib_error_return(0, "vni must be set!");
1119
1120   if (!vrf_is_set && !bd_index_is_set)
1121     return clib_error_return(0, "vrf or bridge domain index must be set!");
1122
1123   a->is_add = is_add;
1124   a->dp_table = vrf_is_set ? table_id : bd_id;
1125   a->vni = vni;
1126   a->is_l2 = bd_index_is_set;
1127
1128   rv = vnet_lisp_gpe_add_del_iface (a, 0);
1129   if (0 != rv)
1130     {
1131       error = clib_error_return(0, "failed to %s gpe iface!",
1132                                 is_add ? "add" : "delete");
1133     }
1134
1135   return error;
1136 }
1137
1138 VLIB_CLI_COMMAND (add_del_lisp_gpe_iface_command, static) = {
1139   .path = "lisp gpe iface",
1140   .short_help = "lisp gpe iface add/del vni <vni> vrf <vrf>",
1141   .function = lisp_gpe_add_del_iface_command_fn,
1142 };