FD.io VPP  v16.06
Vector Packet Processing
interface.c
Go to the documentation of this file.
1 /*
2  * interface.c: mpls interfaces
3  *
4  * Copyright (c) 2012 Cisco and/or its affiliates.
5  * Licensed under the Apache License, Version 2.0 (the "License");
6  * you may not use this file except in compliance with the License.
7  * You may obtain a copy of the License at:
8  *
9  * http://www.apache.org/licenses/LICENSE-2.0
10  *
11  * Unless required by applicable law or agreed to in writing, software
12  * distributed under the License is distributed on an "AS IS" BASIS,
13  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14  * See the License for the specific language governing permissions and
15  * limitations under the License.
16  */
17 
18 #include <vnet/vnet.h>
19 #include <vnet/pg/pg.h>
20 #include <vnet/gre/gre.h>
21 #include <vnet/mpls-gre/mpls.h>
22 
24  u32 sw_if_index,
25  u32 l3_type,
26  void * dst_address,
27  void * rewrite,
28  uword max_rewrite_bytes)
29 {
30  /*
31  * Conundrum: packets from tun/tap destined for the tunnel
32  * actually have this rewrite applied. Transit packets do not.
33  * To make the two cases equivalent, don't generate a
34  * rewrite here, build the entire header in the fast path.
35  */
36  return 0;
37 }
38 
39 /* manually added to the interface output node */
40 #define MPLS_GRE_OUTPUT_NEXT_POST_REWRITE 1
41 
42 static uword
44  vlib_node_runtime_t * node,
45  vlib_frame_t * frame)
46 {
47  mpls_main_t * gm = &mpls_main;
48  vnet_main_t * vnm = gm->vnet_main;
49  u32 next_index;
50  u32 * from, * to_next, n_left_from, n_left_to_next;
51 
52  /* Vector of buffer / pkt indices we're supposed to process */
53  from = vlib_frame_vector_args (frame);
54 
55  /* Number of buffers / pkts */
56  n_left_from = frame->n_vectors;
57 
58  /* Speculatively send the first buffer to the last disposition we used */
59  next_index = node->cached_next_index;
60 
61  while (n_left_from > 0)
62  {
63  /* set up to enqueue to our disposition with index = next_index */
64  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
65 
66  /*
67  * As long as we have enough pkts left to process two pkts
68  * and prefetch two pkts...
69  */
70  while (n_left_from >= 4 && n_left_to_next >= 2)
71  {
72  vlib_buffer_t * b0, * b1;
73  u32 bi0, next0, bi1, next1;
74  mpls_gre_tunnel_t * t0, * t1;
75  u32 sw_if_index0, sw_if_index1;
76  vnet_hw_interface_t * hi0, * hi1;
77  u8 * dst0, * dst1;
78 
79  /* Prefetch the next iteration */
80  {
81  vlib_buffer_t * p2, * p3;
82 
83  p2 = vlib_get_buffer (vm, from[2]);
84  p3 = vlib_get_buffer (vm, from[3]);
85 
86  vlib_prefetch_buffer_header (p2, LOAD);
87  vlib_prefetch_buffer_header (p3, LOAD);
88 
89  /*
90  * Prefetch packet data. We expect to overwrite
91  * the inbound L2 header with an ip header and a
92  * gre header. Might want to prefetch the last line
93  * of rewrite space as well; need profile data
94  */
97  }
98 
99  /* Pick up the next two buffer indices */
100  bi0 = from[0];
101  bi1 = from[1];
102 
103  /* Speculatively enqueue them where we sent the last buffer */
104  to_next[0] = bi0;
105  to_next[1] = bi1;
106  from += 2;
107  to_next += 2;
108  n_left_to_next -= 2;
109  n_left_from -= 2;
110 
111  b0 = vlib_get_buffer (vm, bi0);
112  b1 = vlib_get_buffer (vm, bi1);
113 
114  sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
115  sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
116 
117  /* get h/w intfcs */
118  hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
119  hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
120 
121  /* hw_instance = tunnel pool index */
122  t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance);
123  t1 = pool_elt_at_index (gm->gre_tunnels, hi1->hw_instance);
124 
125  /* Apply rewrite - $$$$$ fixme don't use memcpy */
128 
129  dst0 = vlib_buffer_get_current (b0);
130  dst1 = vlib_buffer_get_current (b1);
131 
132  clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
133  clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
134 
135  /* Fix TX fib indices */
136  vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index;
137  vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->outer_fib_index;
138 
139  /* mpls-post-rewrite takes it from here... */
142 
144  {
145  mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
146  b0, sizeof (*tr));
147  tr->tunnel_id = t0 - gm->gre_tunnels;
148  tr->length = b0->current_length;
149  tr->src.as_u32 = t0->tunnel_src.as_u32;
150  tr->dst.as_u32 = t0->tunnel_dst.as_u32;
151  tr->lookup_miss = 0;
152  tr->mpls_encap_index = t0->encap_index;
153  }
155  {
156  mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
157  b1, sizeof (*tr));
158  tr->tunnel_id = t1 - gm->gre_tunnels;
159  tr->length = b1->current_length;
160  tr->src.as_u32 = t1->tunnel_src.as_u32;
161  tr->dst.as_u32 = t1->tunnel_dst.as_u32;
162  tr->lookup_miss = 0;
163  tr->mpls_encap_index = t1->encap_index;
164  }
165 
166  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
167  to_next, n_left_to_next,
168  bi0, bi1, next0, next1);
169  }
170 
171  while (n_left_from > 0 && n_left_to_next > 0)
172  {
173  vlib_buffer_t * b0;
174  u32 bi0, next0;
175  mpls_gre_tunnel_t * t0;
176  u32 sw_if_index0;
177  vnet_hw_interface_t * hi0;
178  u8 * dst0;
179 
180  bi0 = from[0];
181  to_next[0] = bi0;
182  from += 1;
183  to_next += 1;
184  n_left_from -= 1;
185  n_left_to_next -= 1;
186 
187  b0 = vlib_get_buffer (vm, bi0);
188 
189  sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
190 
191  hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
192 
193  t0 = pool_elt_at_index (gm->gre_tunnels, hi0->hw_instance);
194 
195  /* Apply rewrite - $$$$$ fixme don't use memcpy */
197 
198  dst0 = vlib_buffer_get_current (b0);
199 
200  clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
201 
202  /* Fix the TX fib index */
203  vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->outer_fib_index;
204 
205  /* mpls-post-rewrite takes it from here... */
207 
209  {
210  mpls_gre_tx_trace_t *tr = vlib_add_trace (vm, node,
211  b0, sizeof (*tr));
212  tr->tunnel_id = t0 - gm->gre_tunnels;
213  tr->length = b0->current_length;
214  tr->src.as_u32 = t0->tunnel_src.as_u32;
215  tr->dst.as_u32 = t0->tunnel_dst.as_u32;
216  tr->lookup_miss = 0;
217  tr->mpls_encap_index = t0->encap_index;
218  }
219 
220  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
221  to_next, n_left_to_next,
222  bi0, next0);
223  }
224 
225  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
226  }
227 
229  GRE_ERROR_PKTS_ENCAP, frame->n_vectors);
230 
231  return frame->n_vectors;
232 }
233 
234 static u8 * format_mpls_gre_tunnel_name (u8 * s, va_list * args)
235 {
236  u32 dev_instance = va_arg (*args, u32);
237  return format (s, "mpls-gre%d", dev_instance);
238 }
239 
240 static u8 * format_mpls_gre_device (u8 * s, va_list * args)
241 {
242  u32 dev_instance = va_arg (*args, u32);
243  CLIB_UNUSED (int verbose) = va_arg (*args, int);
244 
245  s = format (s, "MPLS-GRE tunnel: id %d\n", dev_instance);
246  return s;
247 }
248 
250  .name = "MPLS-GRE tunnel device",
251  .format_device_name = format_mpls_gre_tunnel_name,
252  .format_device = format_mpls_gre_device,
253  .format_tx_trace = format_mpls_gre_tx_trace,
254  .tx_function = mpls_gre_interface_tx,
255  .no_flatten_output_chains = 1,
256 #ifdef SOON
257  .clear counter = 0;
258  .admin_up_down_function = 0;
259 #endif
260 };
261 
263  .name = "MPLS-GRE",
264  .format_header = format_mpls_gre_header_with_length,
265 #if 0
266  .unformat_header = unformat_mpls_gre_header,
267 #endif
268  .set_rewrite = mpls_gre_set_rewrite,
269 };
270 
271 
273  u32 sw_if_index,
274  u32 l3_type,
275  void * dst_address,
276  void * rewrite,
277  uword max_rewrite_bytes)
278 {
279  /*
280  * Conundrum: packets from tun/tap destined for the tunnel
281  * actually have this rewrite applied. Transit packets do not.
282  * To make the two cases equivalent, don't generate a
283  * rewrite here, build the entire header in the fast path.
284  */
285  return 0;
286 }
287 
288 /* manually added to the interface output node */
289 #define MPLS_ETH_OUTPUT_NEXT_OUTPUT 1
290 
291 static uword
293  vlib_node_runtime_t * node,
294  vlib_frame_t * frame)
295 {
296  mpls_main_t * gm = &mpls_main;
297  vnet_main_t * vnm = gm->vnet_main;
298  u32 next_index;
299  u32 * from, * to_next, n_left_from, n_left_to_next;
300 
301  /* Vector of buffer / pkt indices we're supposed to process */
302  from = vlib_frame_vector_args (frame);
303 
304  /* Number of buffers / pkts */
305  n_left_from = frame->n_vectors;
306 
307  /* Speculatively send the first buffer to the last disposition we used */
308  next_index = node->cached_next_index;
309 
310  while (n_left_from > 0)
311  {
312  /* set up to enqueue to our disposition with index = next_index */
313  vlib_get_next_frame (vm, node, next_index, to_next, n_left_to_next);
314 
315  /*
316  * As long as we have enough pkts left to process two pkts
317  * and prefetch two pkts...
318  */
319  while (n_left_from >= 4 && n_left_to_next >= 2)
320  {
321  vlib_buffer_t * b0, * b1;
322  u32 bi0, next0, bi1, next1;
323  mpls_eth_tunnel_t * t0, * t1;
324  u32 sw_if_index0, sw_if_index1;
325  vnet_hw_interface_t * hi0, * hi1;
326  u8 * dst0, * dst1;
327 
328  /* Prefetch the next iteration */
329  {
330  vlib_buffer_t * p2, * p3;
331 
332  p2 = vlib_get_buffer (vm, from[2]);
333  p3 = vlib_get_buffer (vm, from[3]);
334 
335  vlib_prefetch_buffer_header (p2, LOAD);
336  vlib_prefetch_buffer_header (p3, LOAD);
337 
338  /*
339  * Prefetch packet data. We expect to overwrite
340  * the inbound L2 header with an ip header and a
341  * gre header. Might want to prefetch the last line
342  * of rewrite space as well; need profile data
343  */
346  }
347 
348  /* Pick up the next two buffer indices */
349  bi0 = from[0];
350  bi1 = from[1];
351 
352  /* Speculatively enqueue them where we sent the last buffer */
353  to_next[0] = bi0;
354  to_next[1] = bi1;
355  from += 2;
356  to_next += 2;
357  n_left_to_next -= 2;
358  n_left_from -= 2;
359 
360  b0 = vlib_get_buffer (vm, bi0);
361  b1 = vlib_get_buffer (vm, bi1);
362 
363  sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
364  sw_if_index1 = vnet_buffer(b1)->sw_if_index [VLIB_TX];
365 
366  /* get h/w intfcs */
367  hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
368  hi1 = vnet_get_sup_hw_interface (vnm, sw_if_index1);
369 
370  /* hw_instance = tunnel pool index */
371  t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
372  t1 = pool_elt_at_index (gm->eth_tunnels, hi1->hw_instance);
373 
374  /* Apply rewrite - $$$$$ fixme don't use memcpy */
377 
378  dst0 = vlib_buffer_get_current (b0);
379  dst1 = vlib_buffer_get_current (b1);
380 
381  clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
382  clib_memcpy (dst1, t1->rewrite_data, vec_len(t1->rewrite_data));
383 
384  /* Fix TX fib indices */
385  vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
386  vnet_buffer(b1)->sw_if_index [VLIB_TX] = t1->tx_sw_if_index;
387 
388  /* mpls-post-rewrite takes it from here... */
391 
393  {
394  mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
395  b0, sizeof (*tr));
396  tr->lookup_miss = 0;
397  tr->tunnel_id = t0 - gm->eth_tunnels;
398  tr->tx_sw_if_index = t0->tx_sw_if_index;
399  tr->mpls_encap_index = t0->encap_index;
400  tr->length = b0->current_length;
401  hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
402  clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
403  }
405  {
406  mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
407  b1, sizeof (*tr));
408  tr->lookup_miss = 0;
409  tr->tunnel_id = t1 - gm->eth_tunnels;
410  tr->tx_sw_if_index = t1->tx_sw_if_index;
411  tr->mpls_encap_index = t1->encap_index;
412  tr->length = b0->current_length;
413  hi1 = vnet_get_sup_hw_interface (vnm, t1->tx_sw_if_index);
414  clib_memcpy (tr->dst, hi1->hw_address, sizeof (tr->dst));
415  }
416 
417  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
418  to_next, n_left_to_next,
419  bi0, bi1, next0, next1);
420  }
421  while (n_left_from > 0 && n_left_to_next > 0)
422  {
423  vlib_buffer_t * b0;
424  u32 bi0, next0;
425  mpls_eth_tunnel_t * t0;
426  u32 sw_if_index0;
427  vnet_hw_interface_t * hi0;
428  u8 * dst0;
429 
430  bi0 = from[0];
431  to_next[0] = bi0;
432  from += 1;
433  to_next += 1;
434  n_left_from -= 1;
435  n_left_to_next -= 1;
436 
437  b0 = vlib_get_buffer (vm, bi0);
438 
439  sw_if_index0 = vnet_buffer(b0)->sw_if_index [VLIB_TX];
440 
441  hi0 = vnet_get_sup_hw_interface (vnm, sw_if_index0);
442 
443  t0 = pool_elt_at_index (gm->eth_tunnels, hi0->hw_instance);
444 
445  /* Apply rewrite - $$$$$ fixme don't use memcpy */
447 
448  dst0 = vlib_buffer_get_current (b0);
449 
450  clib_memcpy (dst0, t0->rewrite_data, vec_len(t0->rewrite_data));
451 
452  /* Fix the TX interface */
453  vnet_buffer(b0)->sw_if_index [VLIB_TX] = t0->tx_sw_if_index;
454 
455  /* Send the packet */
457 
459  {
460  mpls_eth_tx_trace_t *tr = vlib_add_trace (vm, node,
461  b0, sizeof (*tr));
462  tr->lookup_miss = 0;
463  tr->tunnel_id = t0 - gm->eth_tunnels;
464  tr->tx_sw_if_index = t0->tx_sw_if_index;
465  tr->mpls_encap_index = t0->encap_index;
466  tr->length = b0->current_length;
467  hi0 = vnet_get_sup_hw_interface (vnm, t0->tx_sw_if_index);
468  clib_memcpy (tr->dst, hi0->hw_address, sizeof (tr->dst));
469  }
470 
471  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
472  to_next, n_left_to_next,
473  bi0, next0);
474  }
475 
476  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
477  }
478 
480  MPLS_ERROR_PKTS_ENCAP, frame->n_vectors);
481 
482  return frame->n_vectors;
483 }
484 
485 static u8 * format_mpls_eth_tunnel_name (u8 * s, va_list * args)
486 {
487  u32 dev_instance = va_arg (*args, u32);
488  return format (s, "mpls-eth%d", dev_instance);
489 }
490 
491 static u8 * format_mpls_eth_device (u8 * s, va_list * args)
492 {
493  u32 dev_instance = va_arg (*args, u32);
494  CLIB_UNUSED (int verbose) = va_arg (*args, int);
495 
496  s = format (s, "MPLS-ETH tunnel: id %d\n", dev_instance);
497  return s;
498 }
499 
500 VNET_DEVICE_CLASS (mpls_eth_device_class) = {
501  .name = "MPLS-ETH tunnel device",
502  .format_device_name = format_mpls_eth_tunnel_name,
503  .format_device = format_mpls_eth_device,
504  .format_tx_trace = format_mpls_eth_tx_trace,
505  .tx_function = mpls_eth_interface_tx,
506  .no_flatten_output_chains = 1,
507 #ifdef SOON
508  .clear counter = 0;
509  .admin_up_down_function = 0;
510 #endif
511 };
512 
513 
514 VNET_HW_INTERFACE_CLASS (mpls_eth_hw_interface_class) = {
515  .name = "MPLS-ETH",
516  .format_header = format_mpls_eth_header_with_length,
517 #if 0
518  .unformat_header = unformat_mpls_eth_header,
519 #endif
520  .set_rewrite = mpls_eth_set_rewrite,
521 };
522 
523 #define foreach_mpls_post_rewrite_next \
524  _ (IP4_LOOKUP, "ip4-lookup")
525 
526 typedef enum {
527 #define _(s,n) MPLS_POST_REWRITE_NEXT_##s,
529 #undef _
532 
533 
534 static uword
536  vlib_node_runtime_t * node,
537  vlib_frame_t * from_frame)
538 {
539  u32 n_left_from, next_index, * from, * to_next;
540  u16 old_l0 = 0, old_l1 = 0;
541 
542  from = vlib_frame_vector_args (from_frame);
543  n_left_from = from_frame->n_vectors;
544 
545  next_index = node->cached_next_index;
546 
547  while (n_left_from > 0)
548  {
549  u32 n_left_to_next;
550 
551  vlib_get_next_frame (vm, node, next_index,
552  to_next, n_left_to_next);
553 
554  while (n_left_from >= 4 && n_left_to_next >= 2)
555  {
556  u32 bi0, bi1;
557  vlib_buffer_t * b0, * b1;
558  ip4_header_t * ip0, * ip1;
559  u32 next0 = MPLS_POST_REWRITE_NEXT_IP4_LOOKUP;
560  u32 next1 = MPLS_POST_REWRITE_NEXT_IP4_LOOKUP;
561  u16 new_l0, new_l1;
562  ip_csum_t sum0, sum1;
563 
564  /* Prefetch next iteration. */
565  {
566  vlib_buffer_t * p2, * p3;
567 
568  p2 = vlib_get_buffer (vm, from[2]);
569  p3 = vlib_get_buffer (vm, from[3]);
570 
571  vlib_prefetch_buffer_header (p2, LOAD);
572  vlib_prefetch_buffer_header (p3, LOAD);
573 
576  }
577 
578  bi0 = from[0];
579  bi1 = from[1];
580  to_next[0] = bi0;
581  to_next[1] = bi1;
582  from += 2;
583  to_next += 2;
584  n_left_to_next -= 2;
585  n_left_from -= 2;
586 
587 
588  b0 = vlib_get_buffer (vm, bi0);
589  b1 = vlib_get_buffer (vm, bi1);
590  ip0 = vlib_buffer_get_current (b0);
591  ip1 = vlib_buffer_get_current (b1);
592 
593  /* Note: the tunnel rewrite sets up sw_if_index[VLIB_TX] */
594 
595  /* set the GRE (outer) ip packet length, fix the bloody checksum */
596  sum0 = ip0->checksum;
597  sum1 = ip1->checksum;
598 
599  /* old_l0, old_l1 always 0, see the rewrite setup */
600  new_l0 =
601  clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
602  new_l1 =
603  clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b1));
604 
605  sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
606  length /* changed member */);
607  sum1 = ip_csum_update (sum1, old_l1, new_l1, ip4_header_t,
608  length /* changed member */);
609  ip0->checksum = ip_csum_fold (sum0);
610  ip1->checksum = ip_csum_fold (sum1);
611  ip0->length = new_l0;
612  ip1->length = new_l1;
613 
614  vlib_validate_buffer_enqueue_x2 (vm, node, next_index,
615  to_next, n_left_to_next,
616  bi0, bi1, next0, next1);
617  }
618 
619  while (n_left_from > 0 && n_left_to_next > 0)
620  {
621  u32 bi0;
622  vlib_buffer_t * b0;
623  ip4_header_t * ip0;
624  u32 next0 = MPLS_POST_REWRITE_NEXT_IP4_LOOKUP;
625  u16 new_l0;
626  ip_csum_t sum0;
627 
628  bi0 = from[0];
629  to_next[0] = bi0;
630  from += 1;
631  to_next += 1;
632  n_left_from -= 1;
633  n_left_to_next -= 1;
634 
635  b0 = vlib_get_buffer (vm, bi0);
636  ip0 = vlib_buffer_get_current (b0);
637 
638  /* Note: the tunnel rewrite sets up sw_if_index[VLIB_TX] */
639 
640  /* set the GRE (outer) ip packet length, fix the bloody checksum */
641  sum0 = ip0->checksum;
642  /* old_l0 always 0, see the rewrite setup */
643  new_l0 =
644  clib_host_to_net_u16 (vlib_buffer_length_in_chain (vm, b0));
645 
646  sum0 = ip_csum_update (sum0, old_l0, new_l0, ip4_header_t,
647  length /* changed member */);
648  ip0->checksum = ip_csum_fold (sum0);
649  ip0->length = new_l0;
650 
651  vlib_validate_buffer_enqueue_x1 (vm, node, next_index,
652  to_next, n_left_to_next,
653  bi0, next0);
654  }
655 
656  vlib_put_next_frame (vm, node, next_index, n_left_to_next);
657  }
659  MPLS_ERROR_PKTS_ENCAP, from_frame->n_vectors);
660  return from_frame->n_vectors;
661 }
662 
664  .function = mpls_post_rewrite,
665  .name = "mpls-post-rewrite",
666  /* Takes a vector of packets. */
667  .vector_size = sizeof (u32),
668 
669  .runtime_data_bytes = 0,
670 
671  .n_next_nodes = MPLS_POST_REWRITE_N_NEXT,
672  .next_nodes = {
673 #define _(s,n) [MPLS_POST_REWRITE_NEXT_##s] = n,
675 #undef _
676  },
677 };
678 
680 {
681  ip4_header_t * ip0;
682  ip4_gre_and_mpls_header_t * h0;
683  u8 * rewrite_data = 0;
684  mpls_encap_t * e;
686  int i;
687 
688  /* look up the encap label stack using the RX FIB */
690 
691  if (e == 0)
692  {
693  clib_warning ("no label for inner fib index %d, dst %U",
695  &t->tunnel_dst);
696  return 0;
697  }
698 
699  vec_validate (rewrite_data, sizeof (*h0)
700  + sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
701  memset (rewrite_data, 0, sizeof (*h0));
702 
703  h0 = (ip4_gre_and_mpls_header_t *) rewrite_data;
704  /* Copy the encap label stack */
705  lp0 = h0->labels;
706  for (i = 0; i < vec_len(e->labels); i++)
707  lp0[i] = e->labels[i];
708  ip0 = &h0->ip4;
709  h0->gre.protocol = clib_host_to_net_u16(GRE_PROTOCOL_mpls_unicast);
710  ip0->ip_version_and_header_length = 0x45;
711  ip0->ttl = 254;
712  ip0->protocol = IP_PROTOCOL_GRE;
713  /* $$$ fixup ip4 header length and checksum after-the-fact */
716  ip0->checksum = ip4_header_checksum (ip0);
717 
718  return (rewrite_data);
719 }
720 
722  ip4_address_t *dst,
723  ip4_address_t *intfc,
724  u32 mask_width,
725  u32 inner_fib_id, u32 outer_fib_id,
726  u32 * tunnel_sw_if_index,
727  u8 l2_only,
728  u8 is_add)
729 {
730  ip4_main_t * im = &ip4_main;
731  ip_lookup_main_t * lm = &im->lookup_main;
732  mpls_main_t * mm = &mpls_main;
733  vnet_main_t * vnm = vnet_get_main();
734  ip4_address_t zero;
735  mpls_gre_tunnel_t *tp;
736  int need_route_add_del = 1;
737  u32 inner_fib_index = 0;
738  u32 outer_fib_index = 0;
739  ip_adjacency_t adj;
740  u32 adj_index;
741  u8 * rewrite_data;
742  int found_tunnel = 0;
743  mpls_encap_t * e = 0;
744  u32 hw_if_index = ~0;
746  u32 slot;
747  u32 dummy;
748 
749  zero.as_u32 = 0;
750 
751  /* No questions, no answers */
752  if (tunnel_sw_if_index == 0)
753  tunnel_sw_if_index = &dummy;
754 
755  *tunnel_sw_if_index = ~0;
756 
757  if (inner_fib_id != (u32)~0)
758  {
759  uword * p;
760 
761  p = hash_get (im->fib_index_by_table_id, inner_fib_id);
762  if (! p)
763  return VNET_API_ERROR_NO_SUCH_INNER_FIB;
764  inner_fib_index = p[0];
765  }
766 
767  if (outer_fib_id != 0)
768  {
769  uword * p;
770 
771  p = hash_get (im->fib_index_by_table_id, outer_fib_id);
772  if (! p)
773  return VNET_API_ERROR_NO_SUCH_FIB;
774  outer_fib_index = p[0];
775  }
776 
777  /* suppress duplicate mpls interface generation. */
778  pool_foreach (tp, mm->gre_tunnels,
779  ({
780  /*
781  * If we have a tunnel which matches (src, dst, intfc/mask)
782  * AND the expected route is in the FIB, it's a dup
783  */
784  if (!memcmp (&tp->tunnel_src, src, sizeof (*src))
785  && !memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
786  && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
787  && tp->inner_fib_index == inner_fib_index)
788  {
789  ip4_fib_t * fib = vec_elt_at_index (im->fibs, inner_fib_index);
790  uword * hash = fib->adj_index_by_dst_address[mask_width];
791  uword key = intfc->as_u32 & im->fib_masks[mask_width];
792  uword *p = hash_get (hash, key);
793 
794  found_tunnel = 1;
795 
796  if (is_add)
797  {
798  /* A dup, and the route is in the fib. Done */
799  if (p || l2_only)
800  return 1;
801  else
802  {
803  /* Reinstall the route (and other stuff) */
804  e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
805  dst->as_u32);
806  if (e == 0)
807  return VNET_API_ERROR_NO_SUCH_LABEL;
808  goto reinstall_it;
809  }
810  }
811  else
812  {
813  /* Delete, the route is already gone? */
814  if (!p)
815  need_route_add_del = 0;
816  goto add_del_route;
817  }
818 
819  }
820  }));
821 
822  /* Delete, and we can't find the tunnel */
823  if (is_add == 0 && found_tunnel == 0)
824  return VNET_API_ERROR_NO_SUCH_ENTRY;
825 
826  e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, dst->as_u32);
827  if (e == 0)
828  return VNET_API_ERROR_NO_SUCH_LABEL;
829 
830  pool_get(mm->gre_tunnels, tp);
831  memset (tp, 0, sizeof (*tp));
832 
833  if (vec_len (mm->free_gre_sw_if_indices) > 0)
834  {
835  hw_if_index =
836  mm->free_gre_sw_if_indices[vec_len(mm->free_gre_sw_if_indices)-1];
837  _vec_len (mm->free_gre_sw_if_indices) -= 1;
838  hi = vnet_get_hw_interface (vnm, hw_if_index);
839  hi->dev_instance = tp - mm->gre_tunnels;
840  hi->hw_instance = tp - mm->gre_tunnels;
841  }
842  else
843  {
844  hw_if_index = vnet_register_interface
845  (vnm, mpls_gre_device_class.index, tp - mm->gre_tunnels,
847  tp - mm->gre_tunnels);
848  hi = vnet_get_hw_interface (vnm, hw_if_index);
849 
850  /* ... to make the IP and L2 x-connect cases identical */
852  (vnm->vlib_main, hi->tx_node_index,
853  "mpls-post-rewrite", MPLS_GRE_OUTPUT_NEXT_POST_REWRITE);
854 
856  }
857 
858  *tunnel_sw_if_index = hi->sw_if_index;
859  vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
861 
862  tp->hw_if_index = hw_if_index;
863 
864  reinstall_it:
865  tp->tunnel_src.as_u32 = src->as_u32;
866  tp->tunnel_dst.as_u32 = dst->as_u32;
867  tp->intfc_address.as_u32 = intfc->as_u32;
868  tp->mask_width = mask_width;
869  tp->inner_fib_index = inner_fib_index;
870  tp->outer_fib_index = outer_fib_index;
871  tp->encap_index = e - mm->encaps;
872  tp->l2_only = l2_only;
873 
874  /* Create the adjacency and add to v4 fib */
875  memset(&adj, 0, sizeof (adj));
876  adj.explicit_fib_index = ~0;
877  adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
878 
879  rewrite_data = mpls_gre_rewrite (mm, tp);
880  if (rewrite_data == 0)
881  {
882  if (*tunnel_sw_if_index != ~0)
883  {
884  hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
885  vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
886  0 /* admin down */);
887  vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
888  }
889  pool_put (mm->gre_tunnels, tp);
890  return VNET_API_ERROR_NO_SUCH_LABEL;
891  }
892 
893  /* Save a copy of the rewrite data for L2 x-connect */
894  vec_free (tp->rewrite_data);
895 
896  tp->rewrite_data = rewrite_data;
897 
899  (vnm,
900  outer_fib_index /* tx_sw_if_index, aka outer fib ID */,
901  ip4_rewrite_node.index,
903  &adj.rewrite_header,
904  rewrite_data, vec_len(rewrite_data));
905 
906  if (!l2_only)
907  ip_add_adjacency (lm, &adj, 1 /* one adj */,
908  &adj_index);
909 
910  add_del_route:
911 
912  if (need_route_add_del && !l2_only)
913  {
914  if (is_add)
917  &tp->intfc_address,
918  tp->mask_width,
919  &zero /* no next hop */,
920  (u32)~0 /* next_hop_sw_if_index */,
921  1 /* weight */,
922  adj_index,
923  tp->inner_fib_index);
924  else
925  {
927  memset (&a, 0, sizeof (a));
928 
930  a.table_index_or_table_id = tp->inner_fib_index;
931  a.dst_address = tp->intfc_address;
932  a.dst_address_length = tp->mask_width;
933  a.adj_index = ~0;
934 
935  ip4_add_del_route (im, &a);
936  ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
938  }
939  }
940 
941  if (is_add == 0 && found_tunnel)
942  {
943  hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
944  vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
945  0 /* admin down */);
946  vec_add1 (mm->free_gre_sw_if_indices, tp->hw_if_index);
947  vec_free (tp->rewrite_data);
948  pool_put (mm->gre_tunnels, tp);
949  }
950 
951  return 0;
952 }
953 
954 /*
955  * Remove all mpls tunnels in the specified fib
956  */
958 {
959  ip4_main_t * im = &ip4_main;
960  mpls_main_t * mm = &mpls_main;
961  vnet_main_t * vnm = mm->vnet_main;
962  mpls_gre_tunnel_t *tp;
963  u32 fib_index = 0;
964  uword * p;
965  u32 * tunnels_to_delete = 0;
967  ip4_fib_t * fib;
968  int i;
969 
970  p = hash_get (im->fib_index_by_table_id, fib_id);
971  if (! p)
972  return VNET_API_ERROR_NO_SUCH_INNER_FIB;
973  fib_index = p[0];
974 
975  pool_foreach (tp, mm->gre_tunnels,
976  ({
977  if (tp->inner_fib_index == fib_index)
978  vec_add1 (tunnels_to_delete, tp - mm->gre_tunnels);
979  }));
980 
981  fib = vec_elt_at_index (im->fibs, fib_index);
982 
983  for (i = 0; i < vec_len(tunnels_to_delete); i++) {
984  tp = pool_elt_at_index (mm->gre_tunnels, tunnels_to_delete[i]);
985  uword * hash = fib->adj_index_by_dst_address[tp->mask_width];
986  uword key = tp->intfc_address.as_u32 & im->fib_masks[tp->mask_width];
987  uword *p = hash_get (hash, key);
989 
990  /* Delete, the route if not already gone */
991  if (p && !tp->l2_only)
992  {
993  memset (&a, 0, sizeof (a));
996  a.dst_address = tp->intfc_address;
998  a.adj_index = ~0;
999  ip4_add_del_route (im, &a);
1002  }
1003 
1004  hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1006  0 /* admin down */);
1008  vec_free (tp->rewrite_data);
1009  pool_put (mm->gre_tunnels, tp);
1010  }
1011 
1012  vec_free(tunnels_to_delete);
1013 
1014  return (0);
1015 }
1016 
1017 static clib_error_t *
1019  unformat_input_t * input,
1020  vlib_cli_command_t * cmd)
1021 {
1022  unformat_input_t _line_input, * line_input = &_line_input;
1023  ip4_address_t src, dst, intfc;
1024  int src_set = 0, dst_set = 0, intfc_set = 0;
1025  u32 mask_width;
1026  u32 inner_fib_id = (u32)~0;
1027  u32 outer_fib_id = 0;
1028  int rv;
1029  u8 is_del = 0;
1030  u8 l2_only = 0;
1031  u32 tunnel_intfc_sw_if_index = ~0;
1032 
1033  /* Get a line of input. */
1034  if (! unformat_user (input, unformat_line_input, line_input))
1035  return 0;
1036 
1037  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1038  {
1039  if (unformat (line_input, "src %U",
1040  unformat_ip4_address, &src))
1041  src_set = 1;
1042  else if (unformat (line_input, "dst %U",
1043  unformat_ip4_address, &dst))
1044  dst_set = 1;
1045  else if (unformat (line_input, "intfc %U/%d",
1046  unformat_ip4_address, &intfc, &mask_width))
1047  intfc_set = 1;
1048  else if (unformat (line_input, "inner-fib-id %d", &inner_fib_id))
1049  ;
1050  else if (unformat (line_input, "outer-fib-id %d", &outer_fib_id))
1051  ;
1052  else if (unformat (line_input, "del"))
1053  is_del = 1;
1054  else if (unformat (line_input, "l2-only"))
1055  l2_only = 1;
1056  else
1057  return clib_error_return (0, "unknown input '%U'",
1058  format_unformat_error, line_input);
1059  }
1060 
1061  if (!src_set)
1062  return clib_error_return (0, "missing: src <ip-address>");
1063 
1064  if (!dst_set)
1065  return clib_error_return (0, "missing: dst <ip-address>");
1066 
1067  if (!intfc_set)
1068  return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1069 
1070 
1071  rv = vnet_mpls_gre_add_del_tunnel (&src, &dst, &intfc, mask_width,
1072  inner_fib_id, outer_fib_id,
1073  &tunnel_intfc_sw_if_index,
1074  l2_only, !is_del);
1075 
1076  switch (rv)
1077  {
1078  case 0:
1079  break;
1080 
1081  case VNET_API_ERROR_NO_SUCH_INNER_FIB:
1082  return clib_error_return (0, "inner fib ID %d doesn't exist\n",
1083  inner_fib_id);
1084  case VNET_API_ERROR_NO_SUCH_FIB:
1085  return clib_error_return (0, "outer fib ID %d doesn't exist\n",
1086  outer_fib_id);
1087 
1088  case VNET_API_ERROR_NO_SUCH_ENTRY:
1089  return clib_error_return (0, "tunnel not found\n");
1090 
1091  case VNET_API_ERROR_NO_SUCH_LABEL:
1092  /*
1093  * This happens when there's no MPLS label for the dst address
1094  * no need for two error messages.
1095  */
1096  break;
1097 
1098  default:
1099  return clib_error_return (0, "vnet_mpls_gre_add_del_tunnel returned %d",
1100  rv);
1101  }
1102  return 0;
1103 }
1104 
1105 VLIB_CLI_COMMAND (create_mpls_tunnel_command, static) = {
1106  .path = "create mpls gre tunnel",
1107  .short_help =
1108  "create mpls gre tunnel [del] src <addr> dst <addr> intfc <addr>/<mw>",
1110 };
1111 
1112 u8 * format_mpls_encap_index (u8 * s, va_list * args)
1113 {
1114  mpls_main_t * mm = va_arg (*args, mpls_main_t *);
1115  u32 entry_index = va_arg (*args, u32);
1116  mpls_encap_t * e;
1117  int i;
1118 
1119  e = pool_elt_at_index (mm->encaps, entry_index);
1120 
1121  for (i = 0; i < vec_len (e->labels); i++)
1122  s = format
1123  (s, "%d ", vnet_mpls_uc_get_label(clib_net_to_host_u32
1124  (e->labels[i].label_exp_s_ttl)));
1125 
1126  return s;
1127 }
1128 
1129 u8 * format_mpls_gre_tunnel (u8 * s, va_list * args)
1130 {
1131  mpls_gre_tunnel_t * t = va_arg (*args, mpls_gre_tunnel_t *);
1132  mpls_main_t * mm = &mpls_main;
1133 
1134  if (t->l2_only == 0)
1135  {
1136  s = format (s, "[%d]: src %U, dst %U, adj %U/%d, labels %U\n",
1137  t - mm->gre_tunnels,
1141  t->mask_width,
1143 
1144  s = format (s, " inner fib index %d, outer fib index %d",
1146  }
1147  else
1148  {
1149  s = format (s, "[%d]: src %U, dst %U, key %U, labels %U\n",
1150  t - mm->gre_tunnels,
1155 
1156  s = format (s, " l2 interface %d, outer fib index %d",
1157  t->hw_if_index, t->outer_fib_index);
1158  }
1159 
1160  return s;
1161 }
1162 
1163 u8 * format_mpls_ethernet_tunnel (u8 * s, va_list * args)
1164 {
1165  mpls_eth_tunnel_t * t = va_arg (*args, mpls_eth_tunnel_t *);
1166  mpls_main_t * mm = &mpls_main;
1167 
1168  s = format (s, "[%d]: dst %U, adj %U/%d, labels %U\n",
1169  t - mm->eth_tunnels,
1172  t->mask_width,
1174 
1175 
1176  s = format (s, " tx on %U, rx fib index %d",
1178  t->inner_fib_index);
1179 
1180  return s;
1181 }
1182 
1183 static clib_error_t *
1185  unformat_input_t * input,
1186  vlib_cli_command_t * cmd)
1187 {
1188  mpls_main_t * mm = &mpls_main;
1189  mpls_gre_tunnel_t * gt;
1190  mpls_eth_tunnel_t * et;
1191 
1192  if (pool_elts (mm->gre_tunnels))
1193  {
1194  vlib_cli_output (vm, "MPLS-GRE tunnels");
1195  pool_foreach (gt, mm->gre_tunnels,
1196  ({
1197  vlib_cli_output (vm, "%U", format_mpls_gre_tunnel, gt);
1198  }));
1199  }
1200  else
1201  vlib_cli_output (vm, "No MPLS-GRE tunnels");
1202 
1203  if (pool_elts (mm->eth_tunnels))
1204  {
1205  vlib_cli_output (vm, "MPLS-Ethernet tunnels");
1206  pool_foreach (et, mm->eth_tunnels,
1207  ({
1208  vlib_cli_output (vm, "%U", format_mpls_ethernet_tunnel, et);
1209  }));
1210  }
1211  else
1212  vlib_cli_output (vm, "No MPLS-Ethernet tunnels");
1213 
1214  return 0;
1215 }
1216 
1217 VLIB_CLI_COMMAND (show_mpls_tunnel_command, static) = {
1218  .path = "show mpls tunnel",
1219  .short_help = "show mpls tunnel",
1220  .function = show_mpls_tunnel_command_fn,
1221 };
1222 
1223 /* force inclusion from application's main.c */
1225 {
1226  clib_error_t * error;
1227 
1228  if ((error = vlib_call_init_function (vm, mpls_policy_encap_init)))
1229  return error;
1230 
1231  return 0;
1232 }
1234 
1235 
1237 {
1238  u8 * rewrite_data = 0;
1239  mpls_encap_t * e;
1240  mpls_unicast_header_t *lp0;
1241  int i;
1242 
1243  /* look up the encap label stack using the RX FIB and adjacency address*/
1245  t->intfc_address.as_u32);
1246 
1247  if (e == 0)
1248  {
1249  clib_warning ("no label for inner fib index %d, dst %U",
1251  &t->intfc_address);
1252  return 0;
1253  }
1254 
1255  vec_validate (rewrite_data,
1256  sizeof (mpls_unicast_header_t) * vec_len(e->labels) -1);
1257 
1258  /* Copy the encap label stack */
1259  lp0 = (mpls_unicast_header_t *) rewrite_data;
1260 
1261  for (i = 0; i < vec_len(e->labels); i++)
1262  lp0[i] = e->labels[i];
1263 
1264  return (rewrite_data);
1265 }
1266 
1268  ip4_address_t *intfc,
1269  u32 mask_width,
1270  u32 inner_fib_id,
1271  u32 tx_sw_if_index,
1272  u32 * tunnel_sw_if_index,
1273  u8 l2_only,
1274  u8 is_add)
1275 {
1276  ip4_main_t * im = &ip4_main;
1277  ip_lookup_main_t * lm = &im->lookup_main;
1278  mpls_main_t * mm = &mpls_main;
1279  vnet_main_t * vnm = vnet_get_main();
1280  ip4_address_t zero;
1281  mpls_eth_tunnel_t *tp;
1282  int need_route_add_del = 1;
1283  u32 inner_fib_index = 0;
1284  ip_adjacency_t adj;
1285  u32 adj_index;
1286  u8 * rewrite_data;
1287  int found_tunnel = 0;
1288  mpls_encap_t * e = 0;
1289  u32 hw_if_index = ~0;
1291  u32 slot;
1292  u32 dummy;
1293 
1294  zero.as_u32 = 0;
1295 
1296  if (tunnel_sw_if_index == 0)
1297  tunnel_sw_if_index = &dummy;
1298 
1299  *tunnel_sw_if_index = ~0;
1300 
1301  if (inner_fib_id != (u32)~0)
1302  {
1303  uword * p;
1304 
1305  p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1306  if (! p)
1307  return VNET_API_ERROR_NO_SUCH_FIB;
1308  inner_fib_index = p[0];
1309  }
1310 
1311  /* suppress duplicate mpls interface generation. */
1312  pool_foreach (tp, mm->eth_tunnels,
1313  ({
1314  /*
1315  * If we have a tunnel which matches (src, dst, intfc/mask)
1316  * AND the expected route is in the FIB, it's a dup
1317  */
1318  if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1319  && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1320  && tp->inner_fib_index == inner_fib_index)
1321  {
1322  ip4_fib_t * fib = vec_elt_at_index (im->fibs, inner_fib_index);
1323  uword * hash = fib->adj_index_by_dst_address[mask_width];
1324  uword key = intfc->as_u32 & im->fib_masks[mask_width];
1325  uword *p = hash_get (hash, key);
1326 
1327  found_tunnel = 1;
1328 
1329  if (is_add)
1330  {
1331  if (p || l2_only)
1332  return 1;
1333  else
1334  {
1335  e = mpls_encap_by_fib_and_dest (mm, inner_fib_index,
1336  intfc->as_u32);
1337  if (e == 0)
1338  return VNET_API_ERROR_NO_SUCH_LABEL;
1339 
1340  goto reinstall_it;
1341  }
1342  }
1343  else
1344  {
1345  /* Delete, the route is already gone? */
1346  if (!p)
1347  need_route_add_del = 0;
1348  goto add_del_route;
1349  }
1350 
1351  }
1352  }));
1353 
1354  /* Delete, and we can't find the tunnel */
1355  if (is_add == 0 && found_tunnel == 0)
1356  return VNET_API_ERROR_NO_SUCH_ENTRY;
1357 
1358  e = mpls_encap_by_fib_and_dest (mm, inner_fib_index, intfc->as_u32);
1359  if (e == 0)
1360  return VNET_API_ERROR_NO_SUCH_LABEL;
1361 
1362  pool_get(mm->eth_tunnels, tp);
1363  memset (tp, 0, sizeof (*tp));
1364 
1365  if (vec_len (mm->free_eth_sw_if_indices) > 0)
1366  {
1367  hw_if_index =
1368  mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1369  _vec_len (mm->free_eth_sw_if_indices) -= 1;
1370  hi = vnet_get_hw_interface (vnm, hw_if_index);
1371  hi->dev_instance = tp - mm->eth_tunnels;
1372  hi->hw_instance = tp - mm->eth_tunnels;
1373  }
1374  else
1375  {
1376  hw_if_index = vnet_register_interface
1377  (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1378  mpls_eth_hw_interface_class.index,
1379  tp - mm->eth_tunnels);
1380  hi = vnet_get_hw_interface (vnm, hw_if_index);
1381 
1382  /* ... to make the IP and L2 x-connect cases identical */
1384  (vnm->vlib_main, hi->tx_node_index,
1385  "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1386 
1388  }
1389 
1390  *tunnel_sw_if_index = hi->sw_if_index;
1391  vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1393 
1394  tp->hw_if_index = hw_if_index;
1395 
1396  reinstall_it:
1397  clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1398  tp->intfc_address.as_u32 = intfc->as_u32;
1399  tp->mask_width = mask_width;
1400  tp->inner_fib_index = inner_fib_index;
1401  tp->encap_index = e - mm->encaps;
1402  tp->tx_sw_if_index = tx_sw_if_index;
1403  tp->l2_only = l2_only;
1404 
1405  /* Create the adjacency and add to v4 fib */
1406  memset(&adj, 0, sizeof (adj));
1407  adj.explicit_fib_index = ~0;
1408  adj.lookup_next_index = IP_LOOKUP_NEXT_REWRITE;
1409 
1410  rewrite_data = mpls_ethernet_rewrite (mm, tp);
1411  if (rewrite_data == 0)
1412  {
1413  if (*tunnel_sw_if_index != ~0)
1414  {
1415  hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1416  vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1417  0 /* admin down */);
1418  vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1419  }
1420 
1421  pool_put (mm->eth_tunnels, tp);
1422  return VNET_API_ERROR_NO_SUCH_LABEL;
1423  }
1424 
1426  (vnm,
1427  VNET_L3_PACKET_TYPE_MPLS_UNICAST,
1428  tx_sw_if_index,
1429  ip4_rewrite_node.index,
1430  tp->tunnel_dst,
1431  &adj.rewrite_header,
1432  sizeof (adj.rewrite_data));
1433 
1434  /*
1435  * Prepend the (0,1,2) VLAN tag ethernet header
1436  * we just built to the mpls header stack
1437  */
1438  vec_insert (rewrite_data, adj.rewrite_header.data_bytes, 0);
1439  clib_memcpy(rewrite_data,
1440  vnet_rewrite_get_data_internal(&adj.rewrite_header,
1441  sizeof (adj.rewrite_data)),
1442  adj.rewrite_header.data_bytes);
1443 
1444  vnet_rewrite_set_data_internal (&adj.rewrite_header,
1445  sizeof(adj.rewrite_data),
1446  rewrite_data,
1447  vec_len(rewrite_data));
1448 
1449  vec_free (tp->rewrite_data);
1450 
1451  tp->rewrite_data = rewrite_data;
1452 
1453  if (!l2_only)
1454  ip_add_adjacency (lm, &adj, 1 /* one adj */,
1455  &adj_index);
1456 
1457  add_del_route:
1458 
1459  if (need_route_add_del && !l2_only)
1460  {
1461  if (is_add)
1464  &tp->intfc_address,
1465  tp->mask_width,
1466  &zero /* no next hop */,
1467  (u32)~0 /* next_hop_sw_if_index */,
1468  1 /* weight */,
1469  adj_index,
1470  tp->inner_fib_index);
1471  else
1472  {
1474  memset (&a, 0, sizeof (a));
1475 
1477  a.table_index_or_table_id = tp->inner_fib_index;
1478  a.dst_address = tp->intfc_address;
1479  a.dst_address_length = tp->mask_width;
1480  a.adj_index = ~0;
1481 
1482  ip4_add_del_route (im, &a);
1483  ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
1485  }
1486  }
1487  if (is_add == 0 && found_tunnel)
1488  {
1489  hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1490  vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1491  0 /* admin down */);
1492  vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1493  vec_free (tp->rewrite_data);
1494  pool_put (mm->eth_tunnels, tp);
1495  }
1496 
1497  return 0;
1498 }
1499 
1500 static clib_error_t *
1502  unformat_input_t * input,
1503  vlib_cli_command_t * cmd)
1504 {
1505  unformat_input_t _line_input, * line_input = &_line_input;
1506  vnet_main_t * vnm = vnet_get_main();
1507  ip4_address_t intfc;
1508  int adj_set = 0;
1509  u8 dst[6];
1510  int dst_set = 0, intfc_set = 0;
1511  u32 mask_width;
1512  u32 inner_fib_id = (u32)~0;
1513  int rv;
1514  u8 is_del = 0;
1515  u8 l2_only = 0;
1516  u32 tx_sw_if_index;
1517 
1518  /* Get a line of input. */
1519  if (! unformat_user (input, unformat_line_input, line_input))
1520  return 0;
1521 
1522  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1523  {
1524  if (unformat (line_input, "dst %U",
1526  dst_set = 1;
1527  else if (unformat (line_input, "adj %U/%d",
1528  unformat_ip4_address, &intfc, &mask_width))
1529  adj_set = 1;
1530  else if (unformat (line_input, "tx-intfc %U",
1531  unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1532  intfc_set = 1;
1533  else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1534  ;
1535  else if (unformat (line_input, "l2-only"))
1536  l2_only = 1;
1537  else if (unformat (line_input, "del"))
1538  is_del = 1;
1539  else
1540  return clib_error_return (0, "unknown input '%U'",
1541  format_unformat_error, line_input);
1542  }
1543 
1544  if (!intfc_set)
1545  return clib_error_return (0, "missing tx-intfc");
1546 
1547  if (!dst_set)
1548  return clib_error_return (0, "missing: dst <ethernet-address>");
1549 
1550  if (!adj_set)
1551  return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1552 
1553 
1554  rv = vnet_mpls_ethernet_add_del_tunnel (dst, &intfc, mask_width,
1555  inner_fib_id, tx_sw_if_index,
1556  0 /* tunnel sw_if_index */,
1557  l2_only, !is_del);
1558 
1559  switch (rv)
1560  {
1561  case VNET_API_ERROR_NO_SUCH_FIB:
1562  return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1563  inner_fib_id);
1564 
1565  case VNET_API_ERROR_NO_SUCH_ENTRY:
1566  return clib_error_return (0, "tunnel not found\n");
1567 
1568  case VNET_API_ERROR_NO_SUCH_LABEL:
1569  /*
1570  * This happens when there's no MPLS label for the dst address
1571  * no need for two error messages.
1572  */
1573  return clib_error_return (0, "no label for %U in fib %d",
1574  format_ip4_address, &intfc, inner_fib_id);
1575  break;
1576 
1577  default:
1578  break;
1579  }
1580  return 0;
1581 }
1582 
1583 
1584 VLIB_CLI_COMMAND (create_mpls_ethernet_tunnel_command, static) = {
1585  .path = "create mpls ethernet tunnel",
1586  .short_help =
1587  "create mpls ethernet tunnel [del] dst <mac-addr> intfc <addr>/<mw>",
1589 };
1590 
1591 
1593  mpls_encap_t * e,
1594  u32 policy_tunnel_index)
1595 {
1596  mpls_eth_tunnel_t * t;
1597  ip_adjacency_t adj;
1598  u8 * rewrite_data = 0;
1599  u8 * label_start;
1601  int i;
1602 
1603  if (pool_is_free_index (mm->eth_tunnels, policy_tunnel_index))
1604  return VNET_API_ERROR_NO_SUCH_ENTRY;
1605 
1606  t = pool_elt_at_index (mm->eth_tunnels, policy_tunnel_index);
1607 
1608  memset (&adj, 0, sizeof (adj));
1609 
1610  /* Build L2 encap */
1612  (mm->vnet_main,
1613  VNET_L3_PACKET_TYPE_MPLS_UNICAST,
1614  t->tx_sw_if_index,
1615  mpls_policy_encap_node.index,
1616  t->tunnel_dst,
1617  &adj.rewrite_header,
1618  sizeof (adj.rewrite_data));
1619 
1620  vec_validate (rewrite_data, adj.rewrite_header.data_bytes -1);
1621 
1622  clib_memcpy(rewrite_data,
1623  vnet_rewrite_get_data_internal(&adj.rewrite_header,
1624  sizeof (adj.rewrite_data)),
1625  adj.rewrite_header.data_bytes);
1626 
1627  /* Append the label stack */
1628 
1629  vec_add2 (rewrite_data, label_start, vec_len(e->labels) * sizeof (u32));
1630 
1631  lp = (mpls_unicast_header_t *) label_start;
1632 
1633  for (i = 0; i < vec_len(e->labels); i++)
1634  lp[i] = e->labels[i];
1635 
1636  /* Remember the rewrite data */
1637  e->rewrite = rewrite_data;
1638  e->output_next_index = adj.rewrite_header.next_index;
1639 
1640  return 0;
1641 }
1642 
1644  ip4_address_t *intfc,
1645  u32 mask_width,
1646  u32 inner_fib_id,
1647  u32 tx_sw_if_index,
1648  u32 * tunnel_sw_if_index,
1649  u32 classify_table_index,
1650  u32 * new_tunnel_index,
1651  u8 l2_only,
1652  u8 is_add)
1653 {
1654  ip4_main_t * im = &ip4_main;
1655  ip_lookup_main_t * lm = &im->lookup_main;
1656  mpls_main_t * mm = &mpls_main;
1657  vnet_main_t * vnm = vnet_get_main();
1658  ip4_address_t zero;
1659  mpls_eth_tunnel_t *tp;
1660  int need_route_add_del = 1;
1661  u32 inner_fib_index = 0;
1662  ip_adjacency_t adj;
1663  u32 adj_index;
1664  int found_tunnel = 0;
1665  mpls_encap_t * e = 0;
1666  u32 hw_if_index = ~0;
1668  u32 slot;
1669  u32 dummy;
1670 
1671  zero.as_u32 = 0;
1672 
1673  if (tunnel_sw_if_index == 0)
1674  tunnel_sw_if_index = &dummy;
1675 
1676  *tunnel_sw_if_index = ~0;
1677 
1678  if (inner_fib_id != (u32)~0)
1679  {
1680  uword * p;
1681 
1682  p = hash_get (im->fib_index_by_table_id, inner_fib_id);
1683  if (! p)
1684  return VNET_API_ERROR_NO_SUCH_FIB;
1685  inner_fib_index = p[0];
1686  }
1687 
1688  /* suppress duplicate mpls interface generation. */
1689  pool_foreach (tp, mm->eth_tunnels,
1690  ({
1691  /*
1692  * If we have a tunnel which matches (src, dst, intfc/mask)
1693  * AND the expected route is in the FIB, it's a dup
1694  */
1695  if (!memcmp (&tp->tunnel_dst, dst, sizeof (*dst))
1696  && !memcmp (&tp->intfc_address, intfc, sizeof (*intfc))
1697  && tp->inner_fib_index == inner_fib_index)
1698  {
1699  ip4_fib_t * fib = vec_elt_at_index (im->fibs, inner_fib_index);
1700  uword * hash = fib->adj_index_by_dst_address[mask_width];
1701  uword key = intfc->as_u32 & im->fib_masks[mask_width];
1702  uword *p = hash_get (hash, key);
1703 
1704  found_tunnel = 1;
1705 
1706  if (is_add)
1707  {
1708  if (p || l2_only)
1709  return 1;
1710  else
1711  {
1712  goto reinstall_it;
1713  }
1714  }
1715  else
1716  {
1717  /* Delete, the route is already gone? */
1718  if (!p)
1719  need_route_add_del = 0;
1720  goto add_del_route;
1721  }
1722 
1723  }
1724  }));
1725 
1726  /* Delete, and we can't find the tunnel */
1727  if (is_add == 0 && found_tunnel == 0)
1728  return VNET_API_ERROR_NO_SUCH_ENTRY;
1729 
1730  pool_get(mm->eth_tunnels, tp);
1731  memset (tp, 0, sizeof (*tp));
1732 
1733  if (vec_len (mm->free_eth_sw_if_indices) > 0)
1734  {
1735  hw_if_index =
1736  mm->free_eth_sw_if_indices[vec_len(mm->free_eth_sw_if_indices)-1];
1737  _vec_len (mm->free_eth_sw_if_indices) -= 1;
1738  hi = vnet_get_hw_interface (vnm, hw_if_index);
1739  hi->dev_instance = tp - mm->eth_tunnels;
1740  hi->hw_instance = tp - mm->eth_tunnels;
1741  }
1742  else
1743  {
1744  hw_if_index = vnet_register_interface
1745  (vnm, mpls_eth_device_class.index, tp - mm->eth_tunnels,
1746  mpls_eth_hw_interface_class.index,
1747  tp - mm->eth_tunnels);
1748  hi = vnet_get_hw_interface (vnm, hw_if_index);
1749 
1750  /* ... to make the IP and L2 x-connect cases identical */
1752  (vnm->vlib_main, hi->tx_node_index,
1753  "interface-output", MPLS_ETH_OUTPUT_NEXT_OUTPUT);
1754 
1756  }
1757 
1758  *tunnel_sw_if_index = hi->sw_if_index;
1759  vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1761 
1762  tp->hw_if_index = hw_if_index;
1763 
1764  reinstall_it:
1765  clib_memcpy(tp->tunnel_dst, dst, sizeof (tp->tunnel_dst));
1766  tp->intfc_address.as_u32 = intfc->as_u32;
1767  tp->mask_width = mask_width;
1768  tp->inner_fib_index = inner_fib_index;
1769  tp->encap_index = e - mm->encaps;
1770  tp->tx_sw_if_index = tx_sw_if_index;
1771  tp->l2_only = l2_only;
1772 
1773  if (new_tunnel_index)
1774  *new_tunnel_index = tp - mm->eth_tunnels;
1775 
1776  /* Create the classify adjacency and add to v4 fib */
1777  memset(&adj, 0, sizeof (adj));
1778  adj.explicit_fib_index = ~0;
1779  adj.lookup_next_index = IP_LOOKUP_NEXT_CLASSIFY;
1780  adj.classify.table_index = classify_table_index;
1781 
1782  if (!l2_only)
1783  ip_add_adjacency (lm, &adj, 1 /* one adj */,
1784  &adj_index);
1785 
1786  add_del_route:
1787 
1788  if (need_route_add_del && !l2_only)
1789  {
1790  if (is_add)
1793  &tp->intfc_address,
1794  tp->mask_width,
1795  &zero /* no next hop */,
1796  (u32)~0 /* next_hop_sw_if_index */,
1797  1 /* weight */,
1798  adj_index,
1799  tp->inner_fib_index);
1800  else
1801  {
1803  memset (&a, 0, sizeof (a));
1804 
1806  a.table_index_or_table_id = tp->inner_fib_index;
1807  a.dst_address = tp->intfc_address;
1808  a.dst_address_length = tp->mask_width;
1809  a.adj_index = ~0;
1810 
1811  ip4_add_del_route (im, &a);
1812  ip4_maybe_remap_adjacencies (im, tp->inner_fib_index,
1814  }
1815  }
1816  if (is_add == 0 && found_tunnel)
1817  {
1818  hi = vnet_get_hw_interface (vnm, tp->hw_if_index);
1819  vnet_sw_interface_set_flags (vnm, hi->sw_if_index,
1820  0 /* admin down */);
1821  vec_add1 (mm->free_eth_sw_if_indices, tp->hw_if_index);
1822  pool_put (mm->eth_tunnels, tp);
1823  }
1824 
1825  return 0;
1826 }
1827 
1828 static clib_error_t *
1830  unformat_input_t * input,
1831  vlib_cli_command_t * cmd)
1832 {
1833  unformat_input_t _line_input, * line_input = &_line_input;
1834  vnet_main_t * vnm = vnet_get_main();
1835  ip4_address_t intfc;
1836  int adj_set = 0;
1837  u8 dst[6];
1838  int dst_set = 0, intfc_set = 0;
1839  u32 mask_width;
1840  u32 inner_fib_id = (u32)~0;
1841  u32 classify_table_index = (u32)~0;
1842  u32 new_tunnel_index;
1843  int rv;
1844  u8 is_del = 0;
1845  u8 l2_only = 0;
1846  u32 tx_sw_if_index;
1847 
1848  /* Get a line of input. */
1849  if (! unformat_user (input, unformat_line_input, line_input))
1850  return 0;
1851 
1852  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1853  {
1854  if (unformat (line_input, "dst %U",
1856  dst_set = 1;
1857  else if (unformat (line_input, "adj %U/%d",
1858  unformat_ip4_address, &intfc, &mask_width))
1859  adj_set = 1;
1860  else if (unformat (line_input, "tx-intfc %U",
1861  unformat_vnet_sw_interface, vnm, &tx_sw_if_index))
1862  intfc_set = 1;
1863  else if (unformat (line_input, "classify-table-index %d",
1864  &classify_table_index))
1865  ;
1866  else if (unformat (line_input, "fib-id %d", &inner_fib_id))
1867  ;
1868  else if (unformat (line_input, "l2-only"))
1869  l2_only = 1;
1870  else if (unformat (line_input, "del"))
1871  is_del = 1;
1872  else
1873  return clib_error_return (0, "unknown input '%U'",
1874  format_unformat_error, line_input);
1875  }
1876 
1877  if (classify_table_index == ~0)
1878  return clib_error_return (0, "missing classify_table_index");
1879 
1880  if (!intfc_set)
1881  return clib_error_return (0, "missing tx-intfc");
1882 
1883  if (!dst_set)
1884  return clib_error_return (0, "missing: dst <ethernet-address>");
1885 
1886  if (!adj_set)
1887  return clib_error_return (0, "missing: intfc <ip-address>/<mask-width>");
1888 
1889 
1890  rv = vnet_mpls_ethernet_add_del_policy_tunnel (dst, &intfc, mask_width,
1891  inner_fib_id, tx_sw_if_index,
1892  0 /* tunnel sw_if_index */,
1893  classify_table_index,
1894  &new_tunnel_index,
1895  l2_only, !is_del);
1896  switch (rv)
1897  {
1898  case VNET_API_ERROR_NO_SUCH_FIB:
1899  return clib_error_return (0, "rx fib ID %d doesn't exist\n",
1900  inner_fib_id);
1901 
1902  case VNET_API_ERROR_NO_SUCH_ENTRY:
1903  return clib_error_return (0, "tunnel not found\n");
1904 
1905  case VNET_API_ERROR_NO_SUCH_LABEL:
1906  /*
1907  * This happens when there's no MPLS label for the dst address
1908  * no need for two error messages.
1909  */
1910  return clib_error_return (0, "no label for %U in fib %d",
1911  format_ip4_address, &intfc, inner_fib_id);
1912  break;
1913 
1914  default:
1915  break;
1916  }
1917 
1918  if (!is_del)
1919  vlib_cli_output (vm, "tunnel index %d", new_tunnel_index);
1920 
1921  return 0;
1922 }
1923 
1924 VLIB_CLI_COMMAND (create_mpls_ethernet_policy_tunnel_command, static) = {
1925  .path = "create mpls ethernet policy tunnel",
1926  .short_help =
1927  "create mpls ethernet policy tunnel [del] dst <mac-addr> intfc <addr>/<mw>\n"
1928  " classify-table-index <nn>",
1930 };
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:394
void vlib_put_next_frame(vlib_main_t *vm, vlib_node_runtime_t *r, u32 next_index, u32 n_vectors_left)
Definition: main.c:459
u8 * format_mpls_encap_index(u8 *s, va_list *args)
Definition: interface.c:1112
vmrglw vmrglh hi
int vnet_mpls_gre_delete_fib_tunnels(u32 fib_id)
Definition: interface.c:957
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:267
#define CLIB_UNUSED(x)
Definition: clib.h:79
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:942
u32 * free_gre_sw_if_indices
Definition: mpls.h:84
static u32 vnet_mpls_uc_get_label(u32 label_exp_s_ttl)
Definition: packet.h:29
u8 tunnel_dst[6]
Definition: mpls.h:58
a
Definition: bitmap.h:393
void ip4_add_del_route_next_hop(ip4_main_t *im, u32 flags, ip4_address_t *dst_address, u32 dst_address_length, ip4_address_t *next_hop, u32 next_hop_sw_if_index, u32 next_hop_weight, u32 adj_index, u32 explicit_fib_index)
Definition: ip4_forward.c:274
u32 mask_width
Definition: mpls.h:62
ip4_address_t src_address
Definition: ip4_packet.h:138
always_inline void * vnet_rewrite_get_data_internal(vnet_rewrite_header_t *rw, int max_size)
Definition: rewrite.h:111
format_function_t format_mpls_eth_header_with_length
Definition: mpls.h:112
ip4_address_t intfc_address
Definition: mpls.h:47
static uword mpls_gre_set_rewrite(vnet_main_t *vnm, u32 sw_if_index, u32 l3_type, void *dst_address, void *rewrite, uword max_rewrite_bytes)
Definition: interface.c:23
u32 inner_fib_index
Definition: mpls.h:49
#define UNFORMAT_END_OF_INPUT
Definition: format.h:142
int vnet_mpls_ethernet_add_del_tunnel(u8 *dst, ip4_address_t *intfc, u32 mask_width, u32 inner_fib_id, u32 tx_sw_if_index, u32 *tunnel_sw_if_index, u8 l2_only, u8 is_add)
Definition: interface.c:1267
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:480
ip_adjacency_t * ip_add_adjacency(ip_lookup_main_t *lm, ip_adjacency_t *copy_adj, u32 n_adj, u32 *adj_index_return)
Definition: lookup.c:139
static u8 * format_mpls_eth_tunnel_name(u8 *s, va_list *args)
Definition: interface.c:485
static clib_error_t * mpls_policy_encap_init(vlib_main_t *vm)
Definition: policy_encap.c:157
#define vec_add2(V, P, N)
Add N elements to end of vector V, return pointer to new elements in P.
Definition: vec.h:519
ip_lookup_main_t lookup_main
Definition: ip4.h:129
uword ip_csum_t
Definition: ip_packet.h:86
unformat_function_t unformat_vnet_sw_interface
void ip4_maybe_remap_adjacencies(ip4_main_t *im, u32 table_index_or_table_id, u32 flags)
Definition: ip4_forward.c:522
u32 encap_index
Definition: mpls.h:51
#define pool_get(P, E)
Definition: pool.h:186
format_function_t format_ip4_address
Definition: format.h:71
format_function_t format_vnet_sw_if_index_name
always_inline void * vlib_buffer_get_current(vlib_buffer_t *b)
Get pointer to current data to process.
Definition: buffer.h:184
#define MPLS_ETH_OUTPUT_NEXT_OUTPUT
Definition: interface.c:289
ip4_address_t dst
Definition: mpls.h:192
always_inline uword unformat_check_input(unformat_input_t *i)
Definition: format.h:168
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
u8 * format_mpls_eth_tx_trace(u8 *s, va_list *args)
Definition: mpls.c:44
u8 * format_ethernet_address(u8 *s, va_list *args)
Definition: format.c:43
#define pool_foreach(VAR, POOL, BODY)
Definition: pool.h:328
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:109
static u8 * format_mpls_gre_tunnel_name(u8 *s, va_list *args)
Definition: interface.c:234
ip4_address_t dst_address
Definition: ip4_packet.h:138
static uword mpls_post_rewrite(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *from_frame)
Definition: interface.c:535
ip4_address_t src
Definition: mpls.h:191
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
u32 outer_fib_index
Definition: mpls.h:50
always_inline uword pool_elts(void *v)
Definition: pool.h:97
always_inline uword vlib_buffer_length_in_chain(vlib_main_t *vm, vlib_buffer_t *b)
Get length in bytes of the buffer chain.
Definition: buffer_funcs.h:112
#define clib_warning(format, args...)
Definition: error.h:59
uword unformat_user(unformat_input_t *input, unformat_function_t *func,...)
Definition: unformat.c:953
#define vlib_call_init_function(vm, x)
Definition: init.h:159
u32 vnet_register_interface(vnet_main_t *vnm, u32 dev_class_index, u32 dev_instance, u32 hw_class_index, u32 hw_instance)
Definition: interface.c:583
always_inline void * vlib_frame_vector_args(vlib_frame_t *f)
Definition: node_funcs.h:202
mpls_gre_tunnel_t * gre_tunnels
Definition: mpls.h:83
u32 hw_if_index
Definition: mpls.h:52
unformat_function_t unformat_ip4_address
Definition: format.h:68
always_inline u16 ip_csum_fold(ip_csum_t c)
Definition: ip_packet.h:138
ip4_address_t intfc_address
Definition: mpls.h:59
#define hash_get(h, key)
Definition: hash.h:231
#define pool_elt_at_index(p, i)
Definition: pool.h:346
#define vec_insert(V, N, M)
Insert N vector elements starting at element M, initialize new elements to zero (no header...
Definition: vec.h:644
format_function_t format_mpls_gre_header_with_length
Definition: mpls.h:111
uword * fib_index_by_table_id
Definition: ip4.h:141
u16 current_length
Nbytes between current data and the end of this buffer.
Definition: buffer.h:81
vlib_node_registration_t mpls_policy_encap_node
(constructor) VLIB_REGISTER_NODE (mpls_policy_encap_node)
Definition: policy_encap.c:135
mpls_post_rewrite_next_t
Definition: interface.c:526
#define MPLS_GRE_OUTPUT_NEXT_POST_REWRITE
Definition: interface.c:40
#define foreach_mpls_post_rewrite_next
Definition: interface.c:523
#define pool_put(P, E)
Definition: pool.h:200
static uword mpls_eth_set_rewrite(vnet_main_t *vnm, u32 sw_if_index, u32 l3_type, void *dst_address, void *rewrite, uword max_rewrite_bytes)
Definition: interface.c:272
vlib_node_registration_t mpls_input_node
(constructor) VLIB_REGISTER_NODE (mpls_input_node)
Definition: node.c:258
#define PREDICT_FALSE(x)
Definition: clib.h:97
vnet_main_t * vnet_main
Definition: mpls.h:103
static clib_error_t * show_mpls_tunnel_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: interface.c:1184
always_inline void vlib_node_increment_counter(vlib_main_t *vm, u32 node_index, u32 counter_index, u64 increment)
Definition: node_funcs.h:970
u32 tx_sw_if_index
Definition: mpls.h:60
#define vlib_validate_buffer_enqueue_x2(vm, node, next_index, to_next, n_left_to_next, bi0, bi1, next0, next1)
Definition: buffer_node.h:43
void vnet_rewrite_for_tunnel(vnet_main_t *vnm, u32 tx_sw_if_index, u32 rewrite_node_index, u32 post_rewrite_node_index, vnet_rewrite_header_t *rw, u8 *rewrite_data, u32 rewrite_length)
Definition: rewrite.c:216
#define vlib_validate_buffer_enqueue_x1(vm, node, next_index, to_next, n_left_to_next, bi0, next0)
Definition: buffer_node.h:83
#define vlib_get_next_frame(vm, node, next_index, vectors, n_vectors_left)
Definition: node_funcs.h:265
vnet_device_class_t mpls_gre_device_class
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:538
u32 output_next_index
Definition: mpls.h:73
always_inline u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:194
u32 mask_width
Definition: mpls.h:48
VNET_HW_INTERFACE_CLASS(ethernet_hw_interface_class)
u8 * rewrite
Definition: mpls.h:72
u16 n_vectors
Definition: node.h:307
mpls_main_t mpls_main
Definition: mpls.c:21
vlib_node_registration_t ip4_rewrite_node
(constructor) VLIB_REGISTER_NODE (ip4_rewrite_node)
Definition: ip4_forward.c:2778
int vnet_mpls_ethernet_add_del_policy_tunnel(u8 *dst, ip4_address_t *intfc, u32 mask_width, u32 inner_fib_id, u32 tx_sw_if_index, u32 *tunnel_sw_if_index, u32 classify_table_index, u32 *new_tunnel_index, u8 l2_only, u8 is_add)
Definition: interface.c:1643
#define CLIB_PREFETCH(addr, size, type)
Definition: cache.h:82
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:298
void vnet_rewrite_for_sw_interface(vnet_main_t *vnm, vnet_l3_packet_type_t packet_type, u32 sw_if_index, u32 node_index, void *dst_address, vnet_rewrite_header_t *rw, u32 max_rewrite_bytes)
Definition: rewrite.c:187
Definition: ip4.h:47
u8 * rewrite_data
Definition: mpls.h:53
u8 * format_mpls_ethernet_tunnel(u8 *s, va_list *args)
Definition: interface.c:1163
#define clib_memcpy(a, b, c)
Definition: string.h:63
always_inline vnet_hw_interface_t * vnet_get_sup_hw_interface(vnet_main_t *vnm, u32 sw_if_index)
#define pool_is_free_index(P, I)
Definition: pool.h:197
always_inline vnet_hw_interface_t * vnet_get_hw_interface(vnet_main_t *vnm, u32 hw_if_index)
u8 * rewrite_data
Definition: mpls.h:65
mpls_eth_tunnel_t * eth_tunnels
Definition: mpls.h:87
#define IP4_ROUTE_FLAG_DEL
Definition: ip4.h:265
#define VLIB_CLI_COMMAND(x,...)
Definition: cli.h:150
u32 mpls_encap_index
Definition: mpls.h:221
u16 cached_next_index
Definition: node.h:422
#define VNET_SW_INTERFACE_FLAG_ADMIN_UP
Definition: interface.h:373
uword unformat_ethernet_address(unformat_input_t *input, va_list *args)
Definition: format.c:187
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
ip4_fib_t * fibs
Definition: ip4.h:132
clib_error_t * mpls_interface_init(vlib_main_t *vm)
Definition: interface.c:1224
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:87
ip4_address_t dst_address
Definition: ip4.h:284
#define vnet_buffer(b)
Definition: buffer.h:300
#define IP4_ROUTE_FLAG_ADD
Definition: ip4.h:264
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:405
int vnet_mpls_policy_tunnel_add_rewrite(mpls_main_t *mm, mpls_encap_t *e, u32 policy_tunnel_index)
Definition: interface.c:1592
mpls_encap_t * mpls_encap_by_fib_and_dest(mpls_main_t *mm, u32 rx_fib, u32 dst_address)
Definition: mpls.c:156
#define VLIB_BUFFER_IS_TRACED
Definition: buffer.h:91
vlib_node_registration_t mpls_post_rewrite_node
(constructor) VLIB_REGISTER_NODE (mpls_post_rewrite_node)
Definition: interface.c:663
vlib_node_registration_t gre_input_node
(constructor) VLIB_REGISTER_NODE (gre_input_node)
Definition: node.c:414
u64 uword
Definition: types.h:112
vnet_hw_interface_class_t mpls_gre_hw_interface_class
Definition: defs.h:46
unsigned short u16
Definition: types.h:57
static u8 * mpls_ethernet_rewrite(mpls_main_t *mm, mpls_eth_tunnel_t *t)
Definition: interface.c:1236
i64 word
Definition: types.h:111
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
always_inline void vlib_buffer_advance(vlib_buffer_t *b, word l)
Advance current data pointer by the supplied (signed!) amount.
Definition: buffer.h:197
unsigned char u8
Definition: types.h:56
unformat_function_t unformat_mpls_gre_header
Definition: mpls.h:126
static u8 * format_mpls_eth_device(u8 *s, va_list *args)
Definition: interface.c:491
ip4_address_t tunnel_src
Definition: mpls.h:45
always_inline void vnet_rewrite_set_data_internal(vnet_rewrite_header_t *rw, int max_size, void *data, int data_bytes)
Definition: rewrite.h:90
u32 inner_fib_index
Definition: mpls.h:61
#define IP4_ROUTE_FLAG_FIB_INDEX
Definition: ip4.h:267
#define ip_csum_update(sum, old, new, type, field)
Definition: ip_packet.h:133
u32 table_index_or_table_id
Definition: ip4.h:281
u32 encap_index
Definition: mpls.h:63
always_inline void * vlib_add_trace(vlib_main_t *vm, vlib_node_runtime_t *r, vlib_buffer_t *b, u32 n_data_bytes)
Definition: trace_funcs.h:55
u8 * format_mpls_gre_tx_trace(u8 *s, va_list *args)
Definition: mpls.c:23
u32 mpls_encap_index
Definition: mpls.h:185
#define vlib_prefetch_buffer_header(b, type)
Prefetch buffer metadata.
Definition: buffer.h:162
ip4_address_t tunnel_dst
Definition: mpls.h:46
#define VLIB_REGISTER_NODE(x,...)
Definition: node.h:140
ip4_main_t ip4_main
Definition: ip4_forward.c:1394
u8 data[0]
Packet data.
Definition: buffer.h:150
static uword mpls_gre_interface_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: interface.c:43
static clib_error_t * create_mpls_gre_tunnel_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: interface.c:1018
static uword mpls_eth_interface_tx(vlib_main_t *vm, vlib_node_runtime_t *node, vlib_frame_t *frame)
Definition: interface.c:292
static clib_error_t * create_mpls_ethernet_tunnel_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: interface.c:1501
clib_error_t * vnet_sw_interface_set_flags(vnet_main_t *vnm, u32 sw_if_index, u32 flags)
Definition: interface.c:462
static u8 * format_mpls_gre_device(u8 *s, va_list *args)
Definition: interface.c:240
static u8 * mpls_gre_rewrite(mpls_main_t *mm, mpls_gre_tunnel_t *t)
Definition: interface.c:679
uword * adj_index_by_dst_address[33]
Definition: ip4.h:49
#define clib_error_return(e, args...)
Definition: error.h:112
VNET_DEVICE_CLASS(ethernet_simulated_device_class)
u8 ip_version_and_header_length
Definition: ip4_packet.h:108
struct _unformat_input_t unformat_input_t
void ip4_add_del_route(ip4_main_t *im, ip4_add_del_route_args_t *args)
Definition: ip4_forward.c:196
uword vlib_node_add_named_next_with_slot(vlib_main_t *vm, uword node, char *name, uword slot)
Definition: node.c:219
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
u32 flags
buffer flags: VLIB_BUFFER_IS_TRACED: trace this buffer.
Definition: buffer.h:84
u32 tx_sw_if_index
Definition: mpls.h:218
int vnet_mpls_gre_add_del_tunnel(ip4_address_t *src, ip4_address_t *dst, ip4_address_t *intfc, u32 mask_width, u32 inner_fib_id, u32 outer_fib_id, u32 *tunnel_sw_if_index, u8 l2_only, u8 is_add)
Definition: interface.c:721
unformat_function_t unformat_line_input
Definition: format.h:279
always_inline vlib_buffer_t * vlib_get_buffer(vlib_main_t *vm, u32 buffer_index)
Translate buffer index into buffer pointer.
Definition: buffer_funcs.h:69
static clib_error_t * create_mpls_ethernet_policy_tunnel_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: interface.c:1829
mpls_unicast_header_t * labels
Definition: mpls.h:70
mpls_encap_t * encaps
Definition: mpls.h:91
u32 fib_masks[33]
Definition: ip4.h:134
u8 * format_mpls_gre_tunnel(u8 *s, va_list *args)
Definition: interface.c:1129