FD.io VPP  v16.09
Vector Packet Processing
lisp_gpe.c
Go to the documentation of this file.
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  * http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 
16 #include <vnet/lisp-gpe/lisp_gpe.h>
17 #include <vppinfra/math.h>
18 
20 
21 static int
23  locator_pair_t * lp)
24 {
25  u8 *rw = 0;
26  lisp_gpe_header_t *lisp0;
27  int len;
28 
29  if (ip_addr_version (&lp->lcl_loc) == IP4)
30  {
31  ip4_header_t *ip0;
32  ip4_udp_lisp_gpe_header_t *h0;
33  len = sizeof (*h0);
34 
36 
37  h0 = (ip4_udp_lisp_gpe_header_t *) rw;
38 
39  /* Fixed portion of the (outer) ip4 header */
40  ip0 = &h0->ip4;
41  ip0->ip_version_and_header_length = 0x45;
42  ip0->ttl = 254;
43  ip0->protocol = IP_PROTOCOL_UDP;
44 
45  /* we fix up the ip4 header length and checksum after-the-fact */
48  ip0->checksum = ip4_header_checksum (ip0);
49 
50  /* UDP header, randomize src port on something, maybe? */
51  h0->udp.src_port = clib_host_to_net_u16 (4341);
52  h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe);
53 
54  /* LISP-gpe header */
55  lisp0 = &h0->lisp;
56  }
57  else
58  {
59  ip6_header_t *ip0;
60  ip6_udp_lisp_gpe_header_t *h0;
61  len = sizeof (*h0);
62 
64 
65  h0 = (ip6_udp_lisp_gpe_header_t *) rw;
66 
67  /* Fixed portion of the (outer) ip6 header */
68  ip0 = &h0->ip6;
70  clib_host_to_net_u32 (0x6 << 28);
71  ip0->hop_limit = 254;
72  ip0->protocol = IP_PROTOCOL_UDP;
73 
74  /* we fix up the ip6 header length after-the-fact */
77 
78  /* UDP header, randomize src port on something, maybe? */
79  h0->udp.src_port = clib_host_to_net_u16 (4341);
80  h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe);
81 
82  /* LISP-gpe header */
83  lisp0 = &h0->lisp;
84  }
85 
86  lisp0->flags = t->flags;
87  lisp0->ver_res = t->ver_res;
88  lisp0->res = t->res;
89  lisp0->next_protocol = t->next_protocol;
90  lisp0->iid = clib_host_to_net_u32 (t->vni);
91 
92  st->is_ip4 = ip_addr_version (&lp->lcl_loc) == IP4;
93  st->rewrite = rw;
94  return 0;
95 }
96 
97 static int
100 {
101  int cmp = a->weight - b->weight;
102  return (cmp == 0
103  ? a->sub_tunnel_index - b->sub_tunnel_index : (cmp > 0 ? -1 : 1));
104 }
105 
106 /** Computes sub tunnel load balancing vector.
107  * Algorithm is identical to that used for building unequal-cost multipath
108  * adjacencies */
109 static void
111 {
112  uword n_sts, i, n_nsts, n_nsts_left;
113  f64 sum_weight, norm, error, tolerance;
114  normalized_sub_tunnel_weights_t *nsts = 0, *stp;
116  u32 *st_lbv = 0;
117 
118  /* Accept 1% error */
119  tolerance = .01;
120 
121  n_sts = vec_len (sts);
122  vec_validate (nsts, 2 * n_sts - 1);
123 
124  sum_weight = 0;
125  for (i = 0; i < n_sts; i++)
126  {
127  /* Find total weight to normalize weights. */
128  sum_weight += sts[i].weight;
129 
130  /* build normalized sub tunnels vector */
131  nsts[i].weight = sts[i].weight;
132  nsts[i].sub_tunnel_index = i;
133  }
134 
135  n_nsts = n_sts;
136  if (n_sts == 1)
137  {
138  nsts[0].weight = 1;
139  _vec_len (nsts) = 1;
140  goto build_lbv;
141  }
142 
143  /* Sort sub-tunnels by weight */
144  qsort (nsts, n_nsts, sizeof (u32), (void *) weight_cmp);
145 
146  /* Save copies of all next hop weights to avoid being overwritten in loop below. */
147  for (i = 0; i < n_nsts; i++)
148  nsts[n_nsts + i].weight = nsts[i].weight;
149 
150  /* Try larger and larger power of 2 sized blocks until we
151  find one where traffic flows to within 1% of specified weights. */
152  for (n_nsts = max_pow2 (n_sts);; n_nsts *= 2)
153  {
154  error = 0;
155 
156  norm = n_nsts / sum_weight;
157  n_nsts_left = n_nsts;
158  for (i = 0; i < n_sts; i++)
159  {
160  f64 nf = nsts[n_sts + i].weight * norm;
161  word n = flt_round_nearest (nf);
162 
163  n = n > n_nsts_left ? n_nsts_left : n;
164  n_nsts_left -= n;
165  error += fabs (nf - n);
166  nsts[i].weight = n;
167  }
168 
169  nsts[0].weight += n_nsts_left;
170 
171  /* Less than 5% average error per adjacency with this size adjacency block? */
172  if (error <= tolerance * n_nsts)
173  {
174  /* Truncate any next hops with zero weight. */
175  _vec_len (nsts) = i;
176  break;
177  }
178  }
179 
180 build_lbv:
181 
182  /* build load balancing vector */
183  vec_foreach (stp, nsts)
184  {
185  for (i = 0; i < stp[0].weight; i++)
186  vec_add1 (st_lbv, stp[0].sub_tunnel_index);
187  }
188 
189  t->sub_tunnels_lbv = st_lbv;
190  t->sub_tunnels_lbv_count = n_nsts;
191  t->norm_sub_tunnel_weights = nsts;
192 }
193 
194 static void
196 {
198  locator_pair_t *lp = 0;
199  int i;
200 
201  /* create sub-tunnels for all locator pairs */
202  for (i = 0; i < vec_len (t->locator_pairs); i++)
203  {
204  lp = &t->locator_pairs[i];
205  st.locator_pair_index = i;
206  st.parent_index = t - lgm->tunnels;
207  st.weight = lp->weight;
208 
209  /* compute rewrite for sub-tunnel */
210  lisp_gpe_rewrite (t, &st, lp);
211  vec_add1 (t->sub_tunnels, st);
212  }
213 
214  /* normalize weights and compute sub-tunnel load balancing vector */
216 }
217 
218 #define foreach_copy_field \
219 _(encap_fib_index) \
220 _(decap_fib_index) \
221 _(decap_next_index) \
222 _(vni) \
223 _(action)
224 
225 static int
227  u32 * tun_index_res)
228 {
230  lisp_gpe_tunnel_t *t = 0;
232  lisp_gpe_sub_tunnel_t *stp = 0;
233  uword *p;
234 
235  /* prepare tunnel key */
236  memset (&key, 0, sizeof (key));
237 
238  /* fill in the key's remote eid */
239  if (!is_l2)
241  else
242  mac_copy (&key.rmt.mac, &gid_address_mac (&a->rmt_eid));
243 
244  key.vni = clib_host_to_net_u32 (a->vni);
245 
246  p = mhash_get (&lgm->lisp_gpe_tunnel_by_key, &key);
247 
248  if (a->is_add)
249  {
250  /* adding a tunnel: tunnel must not already exist */
251  if (p)
252  return VNET_API_ERROR_INVALID_VALUE;
253 
255  return VNET_API_ERROR_INVALID_DECAP_NEXT;
256 
258  memset (t, 0, sizeof (*t));
259 
260  /* copy from arg structure */
261 #define _(x) t->x = a->x;
263 #undef _
264 
266 
267  /* if vni is non-default */
268  if (a->vni)
269  t->flags = LISP_GPE_FLAGS_I;
270 
271  /* work in lisp-gpe not legacy mode */
272  t->flags |= LISP_GPE_FLAGS_P;
273 
274  /* next proto */
275  if (!is_l2)
276  t->next_protocol = ip_prefix_version (&key.rmt.ippref) == IP4 ?
278  else
280 
281  /* build sub-tunnels for lowest priority locator-pairs */
282  if (!a->is_negative)
283  create_sub_tunnels (lgm, t);
284 
285  mhash_set (&lgm->lisp_gpe_tunnel_by_key, &key, t - lgm->tunnels, 0);
286 
287  /* return tunnel index */
288  if (tun_index_res)
289  tun_index_res[0] = t - lgm->tunnels;
290  }
291  else
292  {
293  /* deleting a tunnel: tunnel must exist */
294  if (!p)
295  {
296  clib_warning ("Tunnel for eid %U doesn't exist!",
298  return VNET_API_ERROR_NO_SUCH_ENTRY;
299  }
300 
301  t = pool_elt_at_index (lgm->tunnels, p[0]);
302 
303  mhash_unset (&lgm->lisp_gpe_tunnel_by_key, &key, 0);
304 
305  vec_foreach (stp, t->sub_tunnels)
306  {
307  vec_free (stp->rewrite);
308  }
309  vec_free (t->sub_tunnels);
311  vec_free (t->locator_pairs);
312  pool_put (lgm->tunnels, t);
313  }
314 
315  return 0;
316 }
317 
318 static int
320  u32 vni, u32 tun_index, u32 n_sub_tun, u8 is_negative,
321  u8 action, u8 ip_ver)
322 {
323  uword *lookup_next_index, *lgpe_sw_if_index, *lnip;
324 
325  memset (adj, 0, sizeof (adj[0]));
326  adj->n_adj = 1;
327  /* fill in lookup_next_index with a 'legal' value to avoid problems */
328  adj->lookup_next_index = (ip_ver == IP4) ?
331 
332  /* positive mapping */
333  if (!is_negative)
334  {
335  /* send packets that hit this adj to lisp-gpe interface output node in
336  * requested vrf. */
337  lnip = (ip_ver == IP4) ?
340  lookup_next_index = hash_get (lnip, table_id);
341  lgpe_sw_if_index = hash_get (lgm->l3_ifaces.sw_if_index_by_vni, vni);
342 
343  /* the assumption is that the interface must've been created before
344  * programming the dp */
345  ASSERT (lookup_next_index != 0 && lgpe_sw_if_index != 0);
346 
347  /* hijack explicit fib index to store lisp interface node index,
348  * if_address_index for the tunnel index and saved lookup next index
349  * for the number of sub tunnels */
350  adj->explicit_fib_index = lookup_next_index[0];
351  adj->if_address_index = tun_index;
352  adj->rewrite_header.sw_if_index = lgpe_sw_if_index[0];
353  adj->saved_lookup_next_index = n_sub_tun;
354  }
355  /* negative mapping */
356  else
357  {
358  adj->rewrite_header.sw_if_index = ~0;
359  adj->rewrite_header.next_index = ~0;
360  adj->if_address_index = tun_index;
361 
362  switch (action)
363  {
364  case LISP_NO_ACTION:
365  /* TODO update timers? */
366  case LISP_FORWARD_NATIVE:
367  /* TODO check if route/next-hop for eid exists in fib and add
368  * more specific for the eid with the next-hop found */
370  /* insert tunnel that always sends map-request */
371  adj->explicit_fib_index = (ip_ver == IP4) ?
372  LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP :
373  LGPE_IP6_LOOKUP_NEXT_LISP_CP_LOOKUP;
374  break;
375  case LISP_DROP:
376  /* for drop fwd entries, just add route, no need to add encap tunnel */
377  adj->explicit_fib_index = (ip_ver == IP4 ?
378  LGPE_IP4_LOOKUP_NEXT_DROP :
379  LGPE_IP6_LOOKUP_NEXT_DROP);
380  break;
381  default:
382  return -1;
383  }
384  }
385  return 0;
386 }
387 
388 static int
391 {
392  ip_adjacency_t adj, *adjp;
394  u32 rv, tun_index = ~0, n_sub_tuns = 0;
395  ip_prefix_t *rmt_pref, *lcl_pref;
396  u8 ip_ver;
397 
398  rmt_pref = &gid_address_ippref (&a->rmt_eid);
399  lcl_pref = &gid_address_ippref (&a->lcl_eid);
400  ip_ver = ip_prefix_version (rmt_pref);
401 
402  /* add/del tunnel to tunnels pool and prepares rewrite */
403  if (0 != a->locator_pairs)
404  {
405  rv = add_del_ip_tunnel (a, 0 /* is_l2 */ , &tun_index);
406  if (rv)
407  {
408  clib_warning ("failed to build tunnel!");
409  return rv;
410  }
411  if (a->is_add)
412  {
413  t = pool_elt_at_index (lgm->tunnels, tun_index);
414  n_sub_tuns = t->sub_tunnels_lbv_count;
415  }
416  }
417 
418  /* setup adjacency for eid */
419  rv = build_ip_adjacency (lgm, &adj, a->table_id, a->vni, tun_index,
420  n_sub_tuns, a->is_negative, a->action, ip_ver);
421 
422  /* add/delete route for eid */
423  rv |= ip_sd_fib_add_del_route (lgm, rmt_pref, lcl_pref, a->table_id, &adj,
424  a->is_add);
425 
426  if (rv)
427  {
428  clib_warning ("failed to insert route for tunnel!");
429  return rv;
430  }
431 
432  /* check that everything worked */
433  if (CLIB_DEBUG && a->is_add)
434  {
435  u32 adj_index;
436  adj_index = ip_sd_fib_get_route (lgm, rmt_pref, lcl_pref, a->table_id);
437  ASSERT (adj_index != 0);
438 
439  adjp = ip_get_adjacency ((ip_ver == IP4) ? lgm->lm4 : lgm->lm6,
440  adj_index);
441 
442  ASSERT (adjp != 0 && adjp->if_address_index == tun_index);
443  }
444 
445  return rv;
446 }
447 
448 static void
449 make_mac_fib_key (BVT (clib_bihash_kv) * kv, u16 bd_index, u8 src_mac[6],
450  u8 dst_mac[6])
451 {
452  kv->key[0] = (((u64) bd_index) << 48) | mac_to_u64 (dst_mac);
453  kv->key[1] = mac_to_u64 (src_mac);
454  kv->key[2] = 0;
455 }
456 
457 u32
458 lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6],
459  u8 dst_mac[6])
460 {
461  int rv;
462  BVT (clib_bihash_kv) kv, value;
463 
464  make_mac_fib_key (&kv, bd_index, src_mac, dst_mac);
465  rv = BV (clib_bihash_search_inline_2) (&lgm->l2_fib, &kv, &value);
466 
467  /* no match, try with src 0, catch all for dst */
468  if (rv != 0)
469  {
470  kv.key[1] = 0;
471  rv = BV (clib_bihash_search_inline_2) (&lgm->l2_fib, &kv, &value);
472  if (rv == 0)
473  return value.value;
474  }
475 
476  return ~0;
477 }
478 
479 u32
480 lisp_l2_fib_add_del_entry (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6],
481  u8 dst_mac[6], u32 val, u8 is_add)
482 {
483  BVT (clib_bihash_kv) kv, value;
484  u32 old_val = ~0;
485 
486  make_mac_fib_key (&kv, bd_index, src_mac, dst_mac);
487 
488  if (BV (clib_bihash_search) (&lgm->l2_fib, &kv, &value) == 0)
489  old_val = value.value;
490 
491  if (!is_add)
492  BV (clib_bihash_add_del) (&lgm->l2_fib, &kv, 0 /* is_add */ );
493  else
494  {
495  kv.value = val;
496  BV (clib_bihash_add_del) (&lgm->l2_fib, &kv, 1 /* is_add */ );
497  }
498  return old_val;
499 }
500 
501 static void
503 {
504  BV (clib_bihash_init) (&lgm->l2_fib, "l2 fib",
507 }
508 
509 static int
512 {
513  int rv;
514  u32 tun_index;
515  bd_main_t *bdm = &bd_main;
516  uword *bd_indexp;
517 
518  /* create tunnel */
519  rv = add_del_ip_tunnel (a, 1 /* is_l2 */ , &tun_index);
520  if (rv)
521  return rv;
522 
523  bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id);
524  if (!bd_indexp)
525  {
526  clib_warning ("bridge domain %d doesn't exist", a->bd_id);
527  return -1;
528  }
529 
530  /* add entry to l2 lisp fib */
531  lisp_l2_fib_add_del_entry (lgm, bd_indexp[0], gid_address_mac (&a->lcl_eid),
532  gid_address_mac (&a->rmt_eid), tun_index,
533  a->is_add);
534  return 0;
535 }
536 
537 
538 int
540  u32 * hw_if_indexp)
541 {
543  u8 type;
544 
546  {
547  clib_warning ("LISP is disabled!");
548  return VNET_API_ERROR_LISP_DISABLED;
549  }
550 
551  type = gid_address_type (&a->rmt_eid);
552  switch (type)
553  {
554  case GID_ADDR_IP_PREFIX:
555  return add_del_ip_fwd_entry (lgm, a);
556  case GID_ADDR_MAC:
557  return add_del_l2_fwd_entry (lgm, a);
558  default:
559  clib_warning ("Forwarding entries for type %d not supported!", type);
560  return -1;
561  }
562 }
563 
564 static clib_error_t *
566  unformat_input_t * input,
567  vlib_cli_command_t * cmd)
568 {
569  unformat_input_t _line_input, *line_input = &_line_input;
570  u8 is_add = 1;
571  ip_address_t lloc, rloc;
572  clib_error_t *error = 0;
573  gid_address_t _reid, *reid = &_reid, _leid, *leid = &_leid;
574  u8 reid_set = 0, leid_set = 0, is_negative = 0, vrf_set = 0, vni_set = 0;
575  u32 vni, vrf, action = ~0, p, w;
576  locator_pair_t pair, *pairs = 0;
577  int rv;
578 
579  /* Get a line of input. */
580  if (!unformat_user (input, unformat_line_input, line_input))
581  return 0;
582 
583  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
584  {
585  if (unformat (line_input, "del"))
586  is_add = 0;
587  else if (unformat (line_input, "add"))
588  is_add = 1;
589  else if (unformat (line_input, "leid %U", unformat_gid_address, leid))
590  {
591  leid_set = 1;
592  }
593  else if (unformat (line_input, "reid %U", unformat_gid_address, reid))
594  {
595  reid_set = 1;
596  }
597  else if (unformat (line_input, "vni %u", &vni))
598  {
599  gid_address_vni (leid) = vni;
600  gid_address_vni (reid) = vni;
601  vni_set = 1;
602  }
603  else if (unformat (line_input, "vrf %u", &vrf))
604  {
605  vrf_set = 1;
606  }
607  else if (unformat (line_input, "negative action %U",
609  {
610  is_negative = 1;
611  }
612  else if (unformat (line_input, "loc-pair %U %U p %d w %d",
613  unformat_ip_address, &lloc,
614  unformat_ip_address, &rloc, &p, &w))
615  {
616  pair.lcl_loc = lloc;
617  pair.rmt_loc = rloc;
618  pair.priority = p;
619  pair.weight = w;
620  vec_add1 (pairs, pair);
621  }
622  else
623  {
624  error = unformat_parse_error (line_input);
625  goto done;
626  }
627  }
628  unformat_free (line_input);
629 
630  if (!vni_set || !vrf_set)
631  {
632  error = clib_error_return (0, "vni and vrf must be set!");
633  goto done;
634  }
635 
636  if (!reid_set)
637  {
638  error = clib_error_return (0, "remote eid must be set!");
639  goto done;
640  }
641 
642  if (is_negative)
643  {
644  if (~0 == action)
645  {
646  error = clib_error_return (0, "no action set for negative tunnel!");
647  goto done;
648  }
649  }
650  else
651  {
652  if (vec_len (pairs) == 0)
653  {
654  error = clib_error_return (0, "expected ip4/ip6 locators.");
655  goto done;
656  }
657  }
658 
659  if (!leid_set)
660  {
661  /* if leid not set, make sure it's the same AFI like reid */
662  gid_address_type (leid) = gid_address_type (reid);
663  if (GID_ADDR_IP_PREFIX == gid_address_type (reid))
665  }
666 
667  /* add fwd entry */
669  memset (a, 0, sizeof (a[0]));
670 
671  a->is_add = is_add;
672  a->vni = vni;
673  a->table_id = vrf;
674  gid_address_copy (&a->lcl_eid, leid);
675  gid_address_copy (&a->rmt_eid, reid);
676  a->locator_pairs = pairs;
677 
679  if (0 != rv)
680  {
681  error = clib_error_return (0, "failed to %s gpe tunnel!",
682  is_add ? "add" : "delete");
683  }
684 
685 done:
686  vec_free (pairs);
687  return error;
688 }
689 
690 /* *INDENT-OFF* */
691 VLIB_CLI_COMMAND (lisp_gpe_add_del_fwd_entry_command, static) = {
692  .path = "lisp gpe tunnel",
693  .short_help = "lisp gpe tunnel add/del vni <vni> vrf <vrf> [leid <leid>]"
694  "reid <reid> [lloc <sloc> rloc <rloc>] [negative action <action>]",
696 };
697 /* *INDENT-ON* */
698 
699 static u8 *
700 format_decap_next (u8 * s, va_list * args)
701 {
702  u32 next_index = va_arg (*args, u32);
703 
704  switch (next_index)
705  {
706  case LISP_GPE_INPUT_NEXT_DROP:
707  return format (s, "drop");
708  case LISP_GPE_INPUT_NEXT_IP4_INPUT:
709  return format (s, "ip4");
710  case LISP_GPE_INPUT_NEXT_IP6_INPUT:
711  return format (s, "ip6");
712  default:
713  return format (s, "unknown %d", next_index);
714  }
715  return s;
716 }
717 
718 u8 *
719 format_lisp_gpe_tunnel (u8 * s, va_list * args)
720 {
721  lisp_gpe_tunnel_t *t = va_arg (*args, lisp_gpe_tunnel_t *);
723  locator_pair_t *lp = 0;
725 
726  s =
727  format (s, "tunnel %d vni %d (0x%x)\n", t - lgm->tunnels, t->vni, t->vni);
728  s =
729  format (s, " fibs: encap %d, decap %d decap next %U\n",
731  t->decap_next_index);
732  s = format (s, " lisp ver %d ", (t->ver_res >> 6));
733 
734 #define _(n,v) if (t->flags & v) s = format (s, "%s-bit ", #n);
736 #undef _
737 
738  s = format (s, "next_protocol %d ver_res %x res %x\n",
739  t->next_protocol, t->ver_res, t->res);
740 
741  s = format (s, " locator-pairs:\n");
742  vec_foreach (lp, t->locator_pairs)
743  {
744  s = format (s, " local: %U remote: %U weight %d\n",
746  &lp->rmt_loc, lp->weight);
747  }
748 
749  s = format (s, " active sub-tunnels:\n");
751  {
753  s = format (s, " local: %U remote: %U weight %d\n", format_ip_address,
754  &lp->lcl_loc, format_ip_address, &lp->rmt_loc, nstw->weight);
755  }
756  return s;
757 }
758 
759 static clib_error_t *
761  unformat_input_t * input,
762  vlib_cli_command_t * cmd)
763 {
766 
767  if (pool_elts (lgm->tunnels) == 0)
768  vlib_cli_output (vm, "No lisp-gpe tunnels configured...");
769 
770  /* *INDENT-OFF* */
771  pool_foreach (t, lgm->tunnels,
772  ({
773  vlib_cli_output (vm, "%U", format_lisp_gpe_tunnel, t);
774  }));
775  /* *INDENT-ON* */
776 
777  return 0;
778 }
779 
780 /* *INDENT-OFF* */
781 VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) =
782 {
783  .path = "show lisp gpe tunnel",
785 };
786 /* *INDENT-ON* */
787 
788 u8
790 {
792 
793  return lgm->is_en;
794 }
795 
796 clib_error_t *
798 {
800  vnet_main_t *vnm = lgm->vnet_main;
801 
802  if (a->is_en)
803  {
804  /* add lgpe_ip4_lookup as possible next_node for ip4 lookup */
805  if (lgm->ip4_lookup_next_lgpe_ip4_lookup == ~0)
806  {
809  lgpe_ip4_lookup_node.index);
810  }
811  /* add lgpe_ip6_lookup as possible next_node for ip6 lookup */
812  if (lgm->ip6_lookup_next_lgpe_ip6_lookup == ~0)
813  {
816  lgpe_ip6_lookup_node.index);
817  }
818  else
819  {
820  /* ask cp to re-add ifaces and defaults */
821  }
822 
823  lgm->is_en = 1;
824  }
825  else
826  {
827  CLIB_UNUSED (uword * val);
828  hash_pair_t *p;
829  u32 *dp_tables = 0, *dp_table;
830  lisp_gpe_tunnel_key_t *tunnels = 0, *tunnel;
832  vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
833 
834  /* remove all tunnels */
835 
836  /* *INDENT-OFF* */
837  mhash_foreach(tunnel, val, &lgm->lisp_gpe_tunnel_by_key, ({
838  vec_add1(tunnels, tunnel[0]);
839  }));
840  /* *INDENT-ON* */
841 
842  vec_foreach (tunnel, tunnels)
843  {
844  memset (at, 0, sizeof (at[0]));
845  at->is_add = 0;
846  if (tunnel->rmt.type == GID_ADDR_IP_PREFIX)
847  {
850  &tunnel->rmt.ippref);
851  }
852  else
853  {
855  mac_copy (&gid_address_mac (&at->rmt_eid), &tunnel->rmt.mac);
856  }
858  }
859  vec_free (tunnels);
860 
861  /* disable all l3 ifaces */
862 
863  /* *INDENT-OFF* */
865  vec_add1(dp_tables, p->key);
866  }));
867  /* *INDENT-ON* */
868 
869  vec_foreach (dp_table, dp_tables)
870  {
871  ai->is_add = 0;
872  ai->table_id = dp_table[0];
873  ai->is_l2 = 0;
874 
875  /* disables interface and removes defaults */
877  }
878 
879  /* disable all l2 ifaces */
880  _vec_len (dp_tables) = 0;
881 
882  /* *INDENT-OFF* */
884  vec_add1(dp_tables, p->key);
885  }));
886  /* *INDENT-ON* */
887 
888  vec_foreach (dp_table, dp_tables)
889  {
890  ai->is_add = 0;
891  ai->bd_id = dp_table[0];
892  ai->is_l2 = 1;
893 
894  /* disables interface and removes defaults */
896  }
897 
898  vec_free (dp_tables);
899  lgm->is_en = 0;
900  }
901 
902  return 0;
903 }
904 
905 static clib_error_t *
907  unformat_input_t * input,
908  vlib_cli_command_t * cmd)
909 {
910  unformat_input_t _line_input, *line_input = &_line_input;
911  u8 is_en = 1;
913 
914  /* Get a line of input. */
915  if (!unformat_user (input, unformat_line_input, line_input))
916  return 0;
917 
918  while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
919  {
920  if (unformat (line_input, "enable"))
921  is_en = 1;
922  else if (unformat (line_input, "disable"))
923  is_en = 0;
924  else
925  {
926  return clib_error_return (0, "parse error: '%U'",
927  format_unformat_error, line_input);
928  }
929  }
930  a->is_en = is_en;
931  return vnet_lisp_gpe_enable_disable (a);
932 }
933 
934 /* *INDENT-OFF* */
935 VLIB_CLI_COMMAND (enable_disable_lisp_gpe_command, static) = {
936  .path = "lisp gpe",
937  .short_help = "lisp gpe [enable|disable]",
939 };
940 /* *INDENT-ON* */
941 
942 static clib_error_t *
944  unformat_input_t * input,
945  vlib_cli_command_t * cmd)
946 {
948  hash_pair_t *p;
949 
950  vlib_cli_output (vm, "%=10s%=12s", "vrf", "hw_if_index");
951 
952  /* *INDENT-OFF* */
954  vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
955  }));
956  /* *INDENT-ON* */
957 
958  if (0 != lgm->l2_ifaces.hw_if_index_by_dp_table)
959  {
960  vlib_cli_output (vm, "%=10s%=12s", "bd_id", "hw_if_index");
961  /* *INDENT-OFF* */
963  vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
964  }));
965  /* *INDENT-ON* */
966  }
967  return 0;
968 }
969 
970 /* *INDENT-OFF* */
971 VLIB_CLI_COMMAND (lisp_show_iface_command) = {
972  .path = "show lisp gpe interface",
973  .short_help = "show lisp gpe interface",
974  .function = lisp_show_iface_command_fn,
975 };
976 /* *INDENT-ON* */
977 
978 u8 *
979 format_vnet_lisp_gpe_status (u8 * s, va_list * args)
980 {
982  return format (s, "%s", lgm->is_en ? "enabled" : "disabled");
983 }
984 
985 clib_error_t *
987 {
989  clib_error_t *error = 0;
990 
991  if ((error = vlib_call_init_function (vm, ip_main_init)))
992  return error;
993 
994  if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
995  return error;
996 
997  lgm->vnet_main = vnet_get_main ();
998  lgm->vlib_main = vm;
999  lgm->im4 = &ip4_main;
1000  lgm->im6 = &ip6_main;
1001  lgm->lm4 = &ip4_main.lookup_main;
1002  lgm->lm6 = &ip6_main.lookup_main;
1005 
1006  mhash_init (&lgm->lisp_gpe_tunnel_by_key, sizeof (uword),
1007  sizeof (lisp_gpe_tunnel_key_t));
1008 
1009  l2_fib_init (lgm);
1010 
1011  udp_register_dst_port (vm, UDP_DST_PORT_lisp_gpe,
1012  lisp_gpe_ip4_input_node.index, 1 /* is_ip4 */ );
1013  udp_register_dst_port (vm, UDP_DST_PORT_lisp_gpe6,
1014  lisp_gpe_ip6_input_node.index, 0 /* is_ip4 */ );
1015  return 0;
1016 }
1017 
1019 
1020 /*
1021  * fd.io coding-style-patch-verification: ON
1022  *
1023  * Local Variables:
1024  * eval: (c-set-style "gnu")
1025  * End:
1026  */
static int add_del_ip_tunnel(vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u8 is_l2, u32 *tun_index_res)
Definition: lisp_gpe.c:226
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:396
static int build_ip_adjacency(lisp_gpe_main_t *lgm, ip_adjacency_t *adj, u32 table_id, u32 vni, u32 tun_index, u32 n_sub_tun, u8 is_negative, u8 action, u8 ip_ver)
Definition: lisp_gpe.c:319
#define gid_address_ip_version(_a)
Definition: lisp_types.h:209
vlib_node_registration_t lisp_gpe_ip4_input_node
(constructor) VLIB_REGISTER_NODE (lisp_gpe_ip4_input_node)
Definition: decap.c:432
sll srl srl sll sra u16x4 i
Definition: vector_sse2.h:343
u32 decap_next_index
Definition: lisp_gpe.h:96
#define gid_address_type(_a)
Definition: lisp_types.h:205
#define CLIB_UNUSED(x)
Definition: clib.h:79
uword unformat(unformat_input_t *i, char *fmt,...)
Definition: unformat.c:966
u32 ip4_lookup_next_lgpe_ip4_lookup
Definition: lisp_gpe.h:199
a
Definition: bitmap.h:516
u16 saved_lookup_next_index
Highest possible perf subgraph arc interposition, e.g.
Definition: lookup.h:189
u8 vnet_lisp_gpe_enable_disable_status(void)
Definition: lisp_gpe.c:789
ip4_address_t src_address
Definition: ip4_packet.h:138
bad routing header type(not 4)") sr_error (NO_MORE_SEGMENTS
u16 n_adj
Number of adjecencies in block.
Definition: lookup.h:176
ip_lookup_next_t lookup_next_index
Definition: lookup.h:180
int vnet_lisp_gpe_add_del_fwd_entry(vnet_lisp_gpe_add_del_fwd_entry_args_t *a, u32 *hw_if_indexp)
Definition: lisp_gpe.c:539
IP unicast adjacency.
Definition: lookup.h:164
#define UNFORMAT_END_OF_INPUT
Definition: format.h:143
clib_error_t * vnet_lisp_gpe_enable_disable(vnet_lisp_gpe_enable_disable_args_t *a)
Definition: lisp_gpe.c:797
uword mhash_unset(mhash_t *h, void *key, uword *old_value)
Definition: mhash.c:353
lisp_gpe_tunnel_t * tunnels
Definition: lisp_gpe.h:175
#define L2_FIB_DEFAULT_HASH_NUM_BUCKETS
Definition: lisp_gpe.h:338
#define mhash_foreach(k, v, mh, body)
Definition: mhash.h:159
uword unformat_ip_address(unformat_input_t *input, va_list *args)
Definition: lisp_types.c:147
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:482
static clib_error_t * show_lisp_gpe_tunnel_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: lisp_gpe.c:760
ip_lookup_main_t lookup_main
Definition: ip4.h:115
#define vec_validate_aligned(V, I, A)
Make sure vector is long enough for given index (no header, specified alignment)
Definition: vec.h:407
uword * lgpe_ip6_lookup_next_index_by_table_id
Definition: lisp_gpe.h:196
ip6_address_t src_address
Definition: ip6_packet.h:298
#define ip_prefix_version(_a)
Definition: lisp_types.h:59
static uword vlib_node_add_next(vlib_main_t *vm, uword node, uword next_node)
Definition: node_funcs.h:1061
vlib_main_t * vlib_main
Definition: lisp_gpe.h:211
ip_prefix_t ippref
Definition: lisp_types.h:99
vlib_node_registration_t ip4_lookup_node
(constructor) VLIB_REGISTER_NODE (ip4_lookup_node)
Definition: ip4_forward.c:1541
uword unformat_negative_mapping_action(unformat_input_t *input, va_list *args)
Definition: lisp_types.c:306
static lisp_gpe_main_t * vnet_lisp_gpe_get_main()
Definition: lisp_gpe.h:222
vnet_main_t * vnet_get_main(void)
Definition: misc.c:45
#define foreach_copy_field
Definition: lisp_gpe.c:218
#define pool_foreach(VAR, POOL, BODY)
Iterate through pool.
Definition: pool.h:348
int clib_bihash_add_del(clib_bihash *h, clib_bihash_kv *add_v, int is_add)
Add or delete a (key,value) pair from a bi-hash table.
ip6_main_t * im6
Definition: lisp_gpe.h:214
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:111
u16 bd_id
Definition: lisp_gpe.h:293
ip4_address_t dst_address
Definition: ip4_packet.h:138
u8 is_add
Definition: lisp_gpe.h:267
#define L2_FIB_DEFAULT_HASH_MEMORY_SIZE
Definition: lisp_gpe.h:339
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
static foreach_gid_address_type_fcns u64 mac_to_u64(u8 *m)
Definition: lisp_types.h:242
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
#define clib_warning(format, args...)
Definition: error.h:59
void ip_address_copy_addr(void *dst, ip_address_t *src)
Definition: lisp_types.c:679
unsigned long u64
Definition: types.h:89
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
static void compute_sub_tunnels_balancing_vector(lisp_gpe_tunnel_t *t)
Computes sub tunnel load balancing vector.
Definition: lisp_gpe.c:110
uword * bd_index_by_bd_id
Definition: l2_bd.h:27
Definition: lisp_gpe.h:265
#define ip_addr_version(_a)
Definition: lisp_types.h:43
vlib_node_registration_t lisp_gpe_ip6_input_node
(constructor) VLIB_REGISTER_NODE (lisp_gpe_ip6_input_node)
Definition: decap.c:454
#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
mhash_t lisp_gpe_tunnel_by_key
Definition: lisp_gpe.h:178
u32 * sub_tunnels_lbv
Definition: lisp_gpe.h:87
vlib_main_t * vlib_main
Definition: vnet.h:80
u32 table_id
Definition: lisp_gpe.h:292
static void make_mac_fib_key(BVT(clib_bihash_kv)*kv, u16 bd_index, u8 src_mac[6], u8 dst_mac[6])
Definition: lisp_gpe.c:449
u32 lisp_l2_fib_lookup(lisp_gpe_main_t *lgm, u16 bd_index, u8 src_mac[6], u8 dst_mac[6])
Definition: lisp_gpe.c:458
static int add_del_l2_fwd_entry(lisp_gpe_main_t *lgm, vnet_lisp_gpe_add_del_fwd_entry_args_t *a)
Definition: lisp_gpe.c:510
#define gid_address_mac(_a)
Definition: lisp_types.h:211
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:214
#define vec_dup(V)
Return copy of vector (no header, no alignment)
Definition: vec.h:334
#define unformat_parse_error(input)
Definition: format.h:267
u32 ip6_lookup_next_lgpe_ip6_lookup
Definition: lisp_gpe.h:200
uword unformat_gid_address(unformat_input_t *input, va_list *args)
Definition: lisp_types.c:271
u8 * format_gid_address(u8 *s, va_list *args)
Definition: lisp_types.c:224
ip_address_t lcl_loc
Definition: lisp_types.h:300
static uword mhash_set(mhash_t *h, void *key, uword new_value, uword *old_value)
Definition: mhash.h:117
static void l2_fib_init(lisp_gpe_main_t *lgm)
Definition: lisp_gpe.c:502
void clib_bihash_init(clib_bihash *h, char *name, u32 nbuckets, uword memory_size)
initialize a bounded index extensible hash table
void vlib_cli_output(vlib_main_t *vm, char *fmt,...)
Definition: cli.c:575
u32 decap_next_index
Definition: lisp_gpe.h:284
#define gid_address_ippref(_a)
Definition: lisp_types.h:206
u8 is_negative
Definition: lisp_gpe.h:270
uword * sw_if_index_by_vni
Definition: lisp_gpe.h:168
BVT(clib_bihash)
Definition: l2_fib.c:577
#define pool_get_aligned(P, E, A)
Allocate an object E from a pool P (general version).
Definition: pool.h:169
u32 sub_tunnels_lbv_count
Definition: lisp_gpe.h:90
u32 vni
Definition: lisp_gpe.h:287
clib_error_t * ip_main_init(vlib_main_t *vm)
Definition: ip_init.c:45
void mhash_init(mhash_t *h, uword n_value_bytes, uword n_key_bytes)
Definition: mhash.c:168
vlib_node_registration_t lgpe_ip4_lookup_node
(constructor) VLIB_REGISTER_NODE (lgpe_ip4_lookup_node)
Definition: ip_forward.c:1029
int ip_sd_fib_add_del_route(lisp_gpe_main_t *lgm, ip_prefix_t *dst_prefix, ip_prefix_t *src_prefix, u32 table_id, ip_adjacency_t *add_adj, u8 is_add)
Definition: ip_forward.c:719
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:300
u32 ip_sd_fib_get_route(lisp_gpe_main_t *lgm, ip_prefix_t *dst_prefix, ip_prefix_t *src_prefix, u32 table_id)
Definition: ip_forward.c:733
static clib_error_t * lisp_show_iface_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: lisp_gpe.c:943
tunnel_lookup_t l2_ifaces
Definition: lisp_gpe.h:208
vnet_main_t * vnet_main
Definition: lisp_gpe.h:212
static int add_del_ip_fwd_entry(lisp_gpe_main_t *lgm, vnet_lisp_gpe_add_del_fwd_entry_args_t *a)
Definition: lisp_gpe.c:389
static f64 fabs(f64 x)
Definition: math.h:50
static uword max_pow2(uword x)
Definition: clib.h:257
static uword * mhash_get(mhash_t *h, void *key)
Definition: mhash.h:110
int vnet_lisp_gpe_add_del_iface(vnet_lisp_gpe_add_del_iface_args_t *a, u32 *hw_if_indexp)
Definition: interface.c:1060
lisp_gpe_main_t lisp_gpe_main
Definition: lisp_gpe.c:19
vlib_node_registration_t ip6_lookup_node
(constructor) VLIB_REGISTER_NODE (ip6_lookup_node)
Definition: ip6_forward.c:1381
struct _gid_address_t gid_address_t
u8 * format_vnet_lisp_gpe_status(u8 *s, va_list *args)
Definition: lisp_gpe.c:979
#define ASSERT(truth)
unsigned int u32
Definition: types.h:88
u8 * format_ip_address(u8 *s, va_list *args)
Definition: lisp_types.c:127
u8 * format_unformat_error(u8 *s, va_list *va)
Definition: unformat.c:91
ip6_main_t ip6_main
Definition: ip6_forward.c:2955
ip_lookup_main_t lookup_main
Definition: ip6.h:110
int clib_bihash_search(clib_bihash *h, clib_bihash_kv *search_v, clib_bihash_kv *return_v)
Search a bi-hash table.
locator_pair_t * locator_pairs
Definition: lisp_gpe.h:80
clib_error_t * lisp_gpe_init(vlib_main_t *vm)
Definition: lisp_gpe.c:986
u8 * format(u8 *s, char *fmt,...)
Definition: format.c:418
uword * hw_if_index_by_dp_table
Definition: lisp_gpe.h:165
static int lisp_gpe_rewrite(lisp_gpe_tunnel_t *t, lisp_gpe_sub_tunnel_t *st, locator_pair_t *lp)
Definition: lisp_gpe.c:22
vlib_node_registration_t lgpe_ip6_lookup_node
(constructor) VLIB_REGISTER_NODE (lgpe_ip6_lookup_node)
Definition: ip_forward.c:1323
gid_address_t rmt_eid
Definition: lisp_gpe.h:275
clib_error_t * ip4_lookup_init(vlib_main_t *vm)
Definition: ip4_forward.c:1581
u64 uword
Definition: types.h:112
u32 ip_version_traffic_class_and_flow_label
Definition: ip6_packet.h:285
normalized_sub_tunnel_weights_t * norm_sub_tunnel_weights
Definition: lisp_gpe.h:93
unsigned short u16
Definition: types.h:57
#define gid_address_vni(_a)
Definition: lisp_types.h:212
VLIB_CLI_COMMAND(set_interface_ip_source_and_port_range_check_command, static)
i64 word
Definition: types.h:111
static word flt_round_nearest(f64 x)
Definition: clib.h:308
void qsort(void *base, uword n, uword size, int(*compar)(const void *, const void *))
Definition: qsort.c:56
static clib_error_t * lisp_gpe_enable_disable_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: lisp_gpe.c:906
ip_lookup_main_t * lm4
Definition: lisp_gpe.h:215
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
double f64
Definition: types.h:142
unsigned char u8
Definition: types.h:56
tunnel_lookup_t l3_ifaces
Definition: lisp_gpe.h:192
ip4_main_t * im4
Definition: lisp_gpe.h:213
#define hash_foreach_pair(p, v, body)
Definition: hash.h:338
static uword max_log2(uword x)
Definition: clib.h:222
u32 lisp_l2_fib_add_del_entry(lisp_gpe_main_t *lgm, u16 bd_index, u8 src_mac[6], u8 dst_mac[6], u32 val, u8 is_add)
Definition: lisp_gpe.c:480
locator_pair_t * locator_pairs
Definition: lisp_gpe.h:278
void gid_address_copy(gid_address_t *dst, gid_address_t *src)
Definition: lisp_types.c:1188
Definition: lisp_types.h:24
void mac_copy(void *dst, void *src)
Definition: lisp_types.c:808
static uword unformat_check_input(unformat_input_t *i)
Definition: format.h:169
static u8 * format_decap_next(u8 *s, va_list *args)
Definition: lisp_gpe.c:700
ip4_main_t ip4_main
Global ip4 main structure.
Definition: ip4_forward.c:1578
ip_address_t rmt_loc
Definition: lisp_types.h:301
u32 if_address_index
Interface address index for this local/arp adjacency.
Definition: lookup.h:172
#define vec_foreach(var, vec)
Vector iterator.
u8 action
Definition: lisp_gpe.h:271
static int weight_cmp(normalized_sub_tunnel_weights_t *a, normalized_sub_tunnel_weights_t *b)
Definition: lisp_gpe.c:98
i16 explicit_fib_index
Force re-lookup in a different FIB.
Definition: lookup.h:185
u8 * format_lisp_gpe_tunnel(u8 *s, va_list *args)
Definition: lisp_gpe.c:719
void udp_register_dst_port(vlib_main_t *vm, udp_dst_port_t dst_port, u32 node_index, u8 is_ip4)
Definition: udp_local.c:461
#define clib_error_return(e, args...)
Definition: error.h:111
u8 ip_version_and_header_length
Definition: ip4_packet.h:108
struct _unformat_input_t unformat_input_t
static void create_sub_tunnels(lisp_gpe_main_t *lgm, lisp_gpe_tunnel_t *t)
Definition: lisp_gpe.c:195
dp_address_t rmt
Definition: lisp_gpe.h:53
ip_lookup_main_t * lm6
Definition: lisp_gpe.h:216
bd_main_t bd_main
Definition: l2_bd.c:35
#define CLIB_CACHE_LINE_BYTES
Definition: cache.h:67
gid_address_t lcl_eid
Definition: lisp_gpe.h:274
unformat_function_t unformat_line_input
Definition: format.h:281
void ip_prefix_copy(void *dst, void *src)
Definition: lisp_types.c:802
uword * lgpe_ip4_lookup_next_index_by_table_id
Definition: lisp_gpe.h:195
static u16 ip4_header_checksum(ip4_header_t *i)
Definition: ip4_packet.h:194
ip6_address_t dst_address
Definition: ip6_packet.h:298
static ip_adjacency_t * ip_get_adjacency(ip_lookup_main_t *lm, u32 adj_index)
Definition: lookup.h:480
static clib_error_t * lisp_gpe_add_del_fwd_entry_command_fn(vlib_main_t *vm, unformat_input_t *input, vlib_cli_command_t *cmd)
Definition: lisp_gpe.c:565
lisp_gpe_sub_tunnel_t * sub_tunnels
Definition: lisp_gpe.h:83
static uword pool_elts(void *v)
Number of active elements in a pool.
Definition: pool.h:109