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