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:
7 * http://www.apache.org/licenses/LICENSE-2.0
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.
17 * @brief Common utility functions for IPv4, IPv6 and L2 LISP-GPE tunnels.
21 #include <vnet/lisp-gpe/lisp_gpe.h>
22 #include <vppinfra/math.h>
24 /** LISP-GPE global state */
25 lisp_gpe_main_t lisp_gpe_main;
28 * @brief Compute IP-UDP-GPE sub-tunnel encap/rewrite header.
30 * @param[in] t Parent of the sub-tunnel.
31 * @param[in] st Sub-tunnel.
32 * @param[in] lp Local and remote locators used in the encap header.
34 * @return 0 on success.
37 lisp_gpe_rewrite (lisp_gpe_tunnel_t * t, lisp_gpe_sub_tunnel_t * st,
41 lisp_gpe_header_t *lisp0;
44 if (ip_addr_version (&lp->lcl_loc) == IP4)
47 ip4_udp_lisp_gpe_header_t *h0;
50 vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
52 h0 = (ip4_udp_lisp_gpe_header_t *) rw;
54 /* Fixed portion of the (outer) ip4 header */
56 ip0->ip_version_and_header_length = 0x45;
58 ip0->protocol = IP_PROTOCOL_UDP;
60 /* we fix up the ip4 header length and checksum after-the-fact */
61 ip_address_copy_addr (&ip0->src_address, &lp->lcl_loc);
62 ip_address_copy_addr (&ip0->dst_address, &lp->rmt_loc);
63 ip0->checksum = ip4_header_checksum (ip0);
65 /* UDP header, randomize src port on something, maybe? */
66 h0->udp.src_port = clib_host_to_net_u16 (4341);
67 h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe);
75 ip6_udp_lisp_gpe_header_t *h0;
78 vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
80 h0 = (ip6_udp_lisp_gpe_header_t *) rw;
82 /* Fixed portion of the (outer) ip6 header */
84 ip0->ip_version_traffic_class_and_flow_label =
85 clib_host_to_net_u32 (0x6 << 28);
87 ip0->protocol = IP_PROTOCOL_UDP;
89 /* we fix up the ip6 header length after-the-fact */
90 ip_address_copy_addr (&ip0->src_address, &lp->lcl_loc);
91 ip_address_copy_addr (&ip0->dst_address, &lp->rmt_loc);
93 /* UDP header, randomize src port on something, maybe? */
94 h0->udp.src_port = clib_host_to_net_u16 (4341);
95 h0->udp.dst_port = clib_host_to_net_u16 (UDP_DST_PORT_lisp_gpe);
101 lisp0->flags = t->flags;
102 lisp0->ver_res = t->ver_res;
104 lisp0->next_protocol = t->next_protocol;
105 lisp0->iid = clib_host_to_net_u32 (t->vni);
107 st->is_ip4 = ip_addr_version (&lp->lcl_loc) == IP4;
113 weight_cmp (normalized_sub_tunnel_weights_t * a,
114 normalized_sub_tunnel_weights_t * b)
116 int cmp = a->weight - b->weight;
118 ? a->sub_tunnel_index - b->sub_tunnel_index : (cmp > 0 ? -1 : 1));
122 * @brief Computes sub-tunnel load balancing vector.
124 * Algorithm is identical to that used for building unequal-cost multipath
125 * adjacencies. Saves normalized sub-tunnel weights and builds load-balancing
126 * vector consisting of list of sub-tunnel indexes replicated according to
129 * @param[in] t Tunnel for which load balancing vector is computed.
132 compute_sub_tunnels_balancing_vector (lisp_gpe_tunnel_t * t)
134 uword n_sts, i, n_nsts, n_nsts_left;
135 f64 sum_weight, norm, error, tolerance;
136 normalized_sub_tunnel_weights_t *nsts = 0, *stp;
137 lisp_gpe_sub_tunnel_t *sts = t->sub_tunnels;
140 /* Accept 1% error */
143 n_sts = vec_len (sts);
144 vec_validate (nsts, 2 * n_sts - 1);
147 for (i = 0; i < n_sts; i++)
149 /* Find total weight to normalize weights. */
150 sum_weight += sts[i].weight;
152 /* build normalized sub tunnels vector */
153 nsts[i].weight = sts[i].weight;
154 nsts[i].sub_tunnel_index = i;
165 /* Sort sub-tunnels by weight */
166 qsort (nsts, n_nsts, sizeof (u32), (void *) weight_cmp);
168 /* Save copies of all next hop weights to avoid being overwritten in loop below. */
169 for (i = 0; i < n_nsts; i++)
170 nsts[n_nsts + i].weight = nsts[i].weight;
172 /* Try larger and larger power of 2 sized blocks until we
173 find one where traffic flows to within 1% of specified weights. */
174 for (n_nsts = max_pow2 (n_sts);; n_nsts *= 2)
178 norm = n_nsts / sum_weight;
179 n_nsts_left = n_nsts;
180 for (i = 0; i < n_sts; i++)
182 f64 nf = nsts[n_sts + i].weight * norm;
183 word n = flt_round_nearest (nf);
185 n = n > n_nsts_left ? n_nsts_left : n;
187 error += fabs (nf - n);
191 nsts[0].weight += n_nsts_left;
193 /* Less than 5% average error per adjacency with this size adjacency block? */
194 if (error <= tolerance * n_nsts)
196 /* Truncate any next hops with zero weight. */
204 /* build load balancing vector */
205 vec_foreach (stp, nsts)
207 for (i = 0; i < stp[0].weight; i++)
208 vec_add1 (st_lbv, stp[0].sub_tunnel_index);
211 t->sub_tunnels_lbv = st_lbv;
212 t->sub_tunnels_lbv_count = n_nsts;
213 t->norm_sub_tunnel_weights = nsts;
216 /** Create sub-tunnels and load-balancing vector for all locator pairs
217 * associated to a tunnel.*/
219 create_sub_tunnels (lisp_gpe_main_t * lgm, lisp_gpe_tunnel_t * t)
221 lisp_gpe_sub_tunnel_t st;
222 locator_pair_t *lp = 0;
225 /* create sub-tunnels for all locator pairs */
226 for (i = 0; i < vec_len (t->locator_pairs); i++)
228 lp = &t->locator_pairs[i];
229 st.locator_pair_index = i;
230 st.parent_index = t - lgm->tunnels;
231 st.weight = lp->weight;
233 /* compute rewrite for sub-tunnel */
234 lisp_gpe_rewrite (t, &st, lp);
235 vec_add1 (t->sub_tunnels, st);
238 /* normalize weights and compute sub-tunnel load balancing vector */
239 compute_sub_tunnels_balancing_vector (t);
242 #define foreach_copy_field \
245 _(decap_next_index) \
250 * @brief Create/delete IP encapsulated tunnel.
252 * Builds GPE tunnel for L2 or L3 packets and populates tunnel pool
253 * @ref lisp_gpe_tunnel_by_key in @ref lisp_gpe_main_t.
255 * @param[in] a Tunnel parameters.
256 * @param[in] is_l2 Flag indicating if encapsulated content is l2.
257 * @param[out] tun_index_res Tunnel index.
259 * @return 0 on success.
262 add_del_ip_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, u8 is_l2,
265 lisp_gpe_main_t *lgm = &lisp_gpe_main;
266 lisp_gpe_tunnel_t *t = 0;
267 lisp_gpe_tunnel_key_t key;
268 lisp_gpe_sub_tunnel_t *stp = 0;
271 /* prepare tunnel key */
272 memset (&key, 0, sizeof (key));
274 /* fill in the key's remote eid */
276 ip_prefix_copy (&key.rmt.ippref, &gid_address_ippref (&a->rmt_eid));
278 mac_copy (&key.rmt.mac, &gid_address_mac (&a->rmt_eid));
280 key.vni = clib_host_to_net_u32 (a->vni);
282 p = mhash_get (&lgm->lisp_gpe_tunnel_by_key, &key);
286 /* adding a tunnel: tunnel must not already exist */
288 return VNET_API_ERROR_INVALID_VALUE;
290 if (a->decap_next_index >= LISP_GPE_INPUT_N_NEXT)
291 return VNET_API_ERROR_INVALID_DECAP_NEXT;
293 pool_get_aligned (lgm->tunnels, t, CLIB_CACHE_LINE_BYTES);
294 memset (t, 0, sizeof (*t));
296 /* copy from arg structure */
297 #define _(x) t->x = a->x;
301 t->locator_pairs = vec_dup (a->locator_pairs);
303 /* if vni is non-default */
305 t->flags = LISP_GPE_FLAGS_I;
307 /* work in lisp-gpe not legacy mode */
308 t->flags |= LISP_GPE_FLAGS_P;
312 t->next_protocol = ip_prefix_version (&key.rmt.ippref) == IP4 ?
313 LISP_GPE_NEXT_PROTO_IP4 : LISP_GPE_NEXT_PROTO_IP6;
315 t->next_protocol = LISP_GPE_NEXT_PROTO_ETHERNET;
317 /* build sub-tunnels for lowest priority locator-pairs */
319 create_sub_tunnels (lgm, t);
321 mhash_set (&lgm->lisp_gpe_tunnel_by_key, &key, t - lgm->tunnels, 0);
323 /* return tunnel index */
325 tun_index_res[0] = t - lgm->tunnels;
329 /* deleting a tunnel: tunnel must exist */
332 clib_warning ("Tunnel for eid %U doesn't exist!",
333 format_gid_address, &a->rmt_eid);
334 return VNET_API_ERROR_NO_SUCH_ENTRY;
337 t = pool_elt_at_index (lgm->tunnels, p[0]);
339 mhash_unset (&lgm->lisp_gpe_tunnel_by_key, &key, 0);
341 vec_foreach (stp, t->sub_tunnels)
343 vec_free (stp->rewrite);
345 vec_free (t->sub_tunnels);
346 vec_free (t->sub_tunnels_lbv);
347 vec_free (t->locator_pairs);
348 pool_put (lgm->tunnels, t);
355 * @brief Build IP adjacency for LISP Source/Dest FIB.
357 * Because LISP forwarding does not follow typical IP forwarding path, the
358 * adjacency's fields are overloaded (i.e., hijacked) to carry LISP specific
359 * data concerning the lisp-gpe interface the packets hitting the adjacency
360 * should be sent to and the tunnel that should be used.
362 * @param[in] lgm Reference to @ref lisp_gpe_main_t.
363 * @param[out] adj Adjacency to be populated.
364 * @param[in] table_id VRF for adjacency.
365 * @param[in] vni Virtual Network identifier (tenant id).
366 * @param[in] tun_index Tunnel index.
367 * @param[in] n_sub_tun Number of sub-tunnels.
368 * @param[in] is_negative Flag to indicate if the adjacency is for a
370 * @param[in] action Action to be taken for negative mapping.
371 * @param[in] ip_ver IP version for the adjacency.
373 * @return 0 on success.
376 build_ip_adjacency (lisp_gpe_main_t * lgm, ip_adjacency_t * adj, u32 table_id,
377 u32 vni, u32 tun_index, u32 n_sub_tun, u8 is_negative,
378 u8 action, u8 ip_ver)
380 uword *lookup_next_index, *lgpe_sw_if_index, *lnip;
382 memset (adj, 0, sizeof (adj[0]));
384 /* fill in lookup_next_index with a 'legal' value to avoid problems */
385 adj->lookup_next_index = (ip_ver == IP4) ?
386 lgm->ip4_lookup_next_lgpe_ip4_lookup :
387 lgm->ip6_lookup_next_lgpe_ip6_lookup;
389 /* positive mapping */
392 /* send packets that hit this adj to lisp-gpe interface output node in
394 lnip = (ip_ver == IP4) ?
395 lgm->lgpe_ip4_lookup_next_index_by_table_id :
396 lgm->lgpe_ip6_lookup_next_index_by_table_id;
397 lookup_next_index = hash_get (lnip, table_id);
398 lgpe_sw_if_index = hash_get (lgm->l3_ifaces.sw_if_index_by_vni, vni);
400 /* the assumption is that the interface must've been created before
401 * programming the dp */
402 ASSERT (lookup_next_index != 0 && lgpe_sw_if_index != 0);
404 /* hijack explicit fib index to store lisp interface node index,
405 * if_address_index for the tunnel index and saved lookup next index
406 * for the number of sub tunnels */
407 adj->explicit_fib_index = lookup_next_index[0];
408 adj->if_address_index = tun_index;
409 adj->rewrite_header.sw_if_index = lgpe_sw_if_index[0];
410 adj->saved_lookup_next_index = n_sub_tun;
412 /* negative mapping */
415 adj->rewrite_header.sw_if_index = ~0;
416 adj->rewrite_header.next_index = ~0;
417 adj->if_address_index = tun_index;
422 /* TODO update timers? */
423 case LISP_FORWARD_NATIVE:
424 /* TODO check if route/next-hop for eid exists in fib and add
425 * more specific for the eid with the next-hop found */
426 case LISP_SEND_MAP_REQUEST:
427 /* insert tunnel that always sends map-request */
428 adj->explicit_fib_index = (ip_ver == IP4) ?
429 LGPE_IP4_LOOKUP_NEXT_LISP_CP_LOOKUP :
430 LGPE_IP6_LOOKUP_NEXT_LISP_CP_LOOKUP;
433 /* for drop fwd entries, just add route, no need to add encap tunnel */
434 adj->explicit_fib_index = (ip_ver == IP4 ?
435 LGPE_IP4_LOOKUP_NEXT_DROP :
436 LGPE_IP6_LOOKUP_NEXT_DROP);
446 * @brief Add/Delete LISP IP forwarding entry.
448 * Coordinates the creation/removal of forwarding entries for IP LISP overlay:
449 * creates lisp-gpe tunnel, builds tunnel customized forwarding entry and
450 * injects new route in Source/Dest FIB.
452 * @param[in] lgm Reference to @ref lisp_gpe_main_t.
453 * @param[in] a Parameters for building the forwarding entry.
455 * @return 0 on success.
458 add_del_ip_fwd_entry (lisp_gpe_main_t * lgm,
459 vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
461 ip_adjacency_t adj, *adjp;
462 lisp_gpe_tunnel_t *t;
463 u32 rv, tun_index = ~0, n_sub_tuns = 0;
464 ip_prefix_t *rmt_pref, *lcl_pref;
467 rmt_pref = &gid_address_ippref (&a->rmt_eid);
468 lcl_pref = &gid_address_ippref (&a->lcl_eid);
469 ip_ver = ip_prefix_version (rmt_pref);
471 /* add/del tunnel to tunnels pool and prepares rewrite */
472 if (0 != a->locator_pairs)
474 rv = add_del_ip_tunnel (a, 0 /* is_l2 */ , &tun_index);
477 clib_warning ("failed to build tunnel!");
482 t = pool_elt_at_index (lgm->tunnels, tun_index);
483 n_sub_tuns = t->sub_tunnels_lbv_count;
487 /* setup adjacency for eid */
488 rv = build_ip_adjacency (lgm, &adj, a->table_id, a->vni, tun_index,
489 n_sub_tuns, a->is_negative, a->action, ip_ver);
491 /* add/delete route for eid */
492 rv |= ip_sd_fib_add_del_route (lgm, rmt_pref, lcl_pref, a->table_id, &adj,
497 clib_warning ("failed to insert route for tunnel!");
501 /* check that everything worked */
502 if (CLIB_DEBUG && a->is_add)
505 adj_index = ip_sd_fib_get_route (lgm, rmt_pref, lcl_pref, a->table_id);
506 ASSERT (adj_index != 0);
508 adjp = ip_get_adjacency ((ip_ver == IP4) ? lgm->lm4 : lgm->lm6,
511 ASSERT (adjp != 0 && adjp->if_address_index == tun_index);
518 make_mac_fib_key (BVT (clib_bihash_kv) * kv, u16 bd_index, u8 src_mac[6],
521 kv->key[0] = (((u64) bd_index) << 48) | mac_to_u64 (dst_mac);
522 kv->key[1] = mac_to_u64 (src_mac);
527 * @brief Lookup L2 SD FIB entry
529 * Does a vni + dest + source lookup in the L2 LISP FIB. If the lookup fails
530 * it tries a second time with source set to 0 (i.e., a simple dest lookup).
532 * @param[in] lgm Reference to @ref lisp_gpe_main_t.
533 * @param[in] bd_index Bridge domain index.
534 * @param[in] src_mac Source mac address.
535 * @param[in] dst_mac Destination mac address.
537 * @return index of mapping matching the lookup key.
540 lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6],
544 BVT (clib_bihash_kv) kv, value;
546 make_mac_fib_key (&kv, bd_index, src_mac, dst_mac);
547 rv = BV (clib_bihash_search_inline_2) (&lgm->l2_fib, &kv, &value);
549 /* no match, try with src 0, catch all for dst */
553 rv = BV (clib_bihash_search_inline_2) (&lgm->l2_fib, &kv, &value);
562 * @brief Add/del L2 SD FIB entry
564 * Inserts value in L2 FIB keyed by vni + dest + source. If entry is
565 * overwritten the associated value is returned.
567 * @param[in] lgm Reference to @ref lisp_gpe_main_t.
568 * @param[in] bd_index Bridge domain index.
569 * @param[in] src_mac Source mac address.
570 * @param[in] dst_mac Destination mac address.
571 * @param[in] val Value to add.
572 * @param[in] is_add Add/del flag.
574 * @return ~0 or value of overwritten entry.
577 lisp_l2_fib_add_del_entry (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6],
578 u8 dst_mac[6], u32 val, u8 is_add)
580 BVT (clib_bihash_kv) kv, value;
583 make_mac_fib_key (&kv, bd_index, src_mac, dst_mac);
585 if (BV (clib_bihash_search) (&lgm->l2_fib, &kv, &value) == 0)
586 old_val = value.value;
589 BV (clib_bihash_add_del) (&lgm->l2_fib, &kv, 0 /* is_add */ );
593 BV (clib_bihash_add_del) (&lgm->l2_fib, &kv, 1 /* is_add */ );
599 l2_fib_init (lisp_gpe_main_t * lgm)
601 BV (clib_bihash_init) (&lgm->l2_fib, "l2 fib",
602 1 << max_log2 (L2_FIB_DEFAULT_HASH_NUM_BUCKETS),
603 L2_FIB_DEFAULT_HASH_MEMORY_SIZE);
607 * @brief Add/Delete LISP L2 forwarding entry.
609 * Coordinates the creation/removal of forwarding entries for L2 LISP overlay:
610 * creates lisp-gpe tunnel and injects new entry in Source/Dest L2 FIB.
612 * @param[in] lgm Reference to @ref lisp_gpe_main_t.
613 * @param[in] a Parameters for building the forwarding entry.
615 * @return 0 on success.
618 add_del_l2_fwd_entry (lisp_gpe_main_t * lgm,
619 vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
623 bd_main_t *bdm = &bd_main;
627 rv = add_del_ip_tunnel (a, 1 /* is_l2 */ , &tun_index);
631 bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id);
634 clib_warning ("bridge domain %d doesn't exist", a->bd_id);
638 /* add entry to l2 lisp fib */
639 lisp_l2_fib_add_del_entry (lgm, bd_indexp[0], gid_address_mac (&a->lcl_eid),
640 gid_address_mac (&a->rmt_eid), tun_index,
646 * @brief Forwarding entry create/remove dispatcher.
648 * Calls l2 or l3 forwarding entry add/del function based on input data.
650 * @param[in] a Forwarding entry parameters.
651 * @param[out] hw_if_indexp NOT USED
653 * @return 0 on success.
656 vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
659 lisp_gpe_main_t *lgm = &lisp_gpe_main;
662 if (vnet_lisp_gpe_enable_disable_status () == 0)
664 clib_warning ("LISP is disabled!");
665 return VNET_API_ERROR_LISP_DISABLED;
668 type = gid_address_type (&a->rmt_eid);
671 case GID_ADDR_IP_PREFIX:
672 return add_del_ip_fwd_entry (lgm, a);
674 return add_del_l2_fwd_entry (lgm, a);
676 clib_warning ("Forwarding entries for type %d not supported!", type);
681 /** CLI command to add/del forwarding entry. */
682 static clib_error_t *
683 lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm,
684 unformat_input_t * input,
685 vlib_cli_command_t * cmd)
687 unformat_input_t _line_input, *line_input = &_line_input;
689 ip_address_t lloc, rloc;
690 clib_error_t *error = 0;
691 gid_address_t _reid, *reid = &_reid, _leid, *leid = &_leid;
692 u8 reid_set = 0, leid_set = 0, is_negative = 0, vrf_set = 0, vni_set = 0;
693 u32 vni, vrf, action = ~0, p, w;
694 locator_pair_t pair, *pairs = 0;
697 /* Get a line of input. */
698 if (!unformat_user (input, unformat_line_input, line_input))
701 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
703 if (unformat (line_input, "del"))
705 else if (unformat (line_input, "add"))
707 else if (unformat (line_input, "leid %U", unformat_gid_address, leid))
711 else if (unformat (line_input, "reid %U", unformat_gid_address, reid))
715 else if (unformat (line_input, "vni %u", &vni))
717 gid_address_vni (leid) = vni;
718 gid_address_vni (reid) = vni;
721 else if (unformat (line_input, "vrf %u", &vrf))
725 else if (unformat (line_input, "negative action %U",
726 unformat_negative_mapping_action, &action))
730 else if (unformat (line_input, "loc-pair %U %U p %d w %d",
731 unformat_ip_address, &lloc,
732 unformat_ip_address, &rloc, &p, &w))
738 vec_add1 (pairs, pair);
742 error = unformat_parse_error (line_input);
746 unformat_free (line_input);
748 if (!vni_set || !vrf_set)
750 error = clib_error_return (0, "vni and vrf must be set!");
756 error = clib_error_return (0, "remote eid must be set!");
764 error = clib_error_return (0, "no action set for negative tunnel!");
770 if (vec_len (pairs) == 0)
772 error = clib_error_return (0, "expected ip4/ip6 locators.");
779 /* if leid not set, make sure it's the same AFI like reid */
780 gid_address_type (leid) = gid_address_type (reid);
781 if (GID_ADDR_IP_PREFIX == gid_address_type (reid))
782 gid_address_ip_version (leid) = gid_address_ip_version (reid);
786 vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
787 memset (a, 0, sizeof (a[0]));
792 gid_address_copy (&a->lcl_eid, leid);
793 gid_address_copy (&a->rmt_eid, reid);
794 a->locator_pairs = pairs;
796 rv = vnet_lisp_gpe_add_del_fwd_entry (a, 0);
799 error = clib_error_return (0, "failed to %s gpe tunnel!",
800 is_add ? "add" : "delete");
809 VLIB_CLI_COMMAND (lisp_gpe_add_del_fwd_entry_command, static) = {
810 .path = "lisp gpe tunnel",
811 .short_help = "lisp gpe tunnel add/del vni <vni> vrf <vrf> [leid <leid>]"
812 "reid <reid> [loc-pair <lloc> <rloc> p <priority> w <weight>] "
813 "[negative action <action>]",
814 .function = lisp_gpe_add_del_fwd_entry_command_fn,
818 /** Format LISP-GPE next indexes. */
820 format_decap_next (u8 * s, va_list * args)
822 u32 next_index = va_arg (*args, u32);
826 case LISP_GPE_INPUT_NEXT_DROP:
827 return format (s, "drop");
828 case LISP_GPE_INPUT_NEXT_IP4_INPUT:
829 return format (s, "ip4");
830 case LISP_GPE_INPUT_NEXT_IP6_INPUT:
831 return format (s, "ip6");
833 return format (s, "unknown %d", next_index);
838 /** Format LISP-GPE tunnel. */
840 format_lisp_gpe_tunnel (u8 * s, va_list * args)
842 lisp_gpe_tunnel_t *t = va_arg (*args, lisp_gpe_tunnel_t *);
843 lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
844 locator_pair_t *lp = 0;
845 normalized_sub_tunnel_weights_t *nstw;
848 format (s, "tunnel %d vni %d (0x%x)\n", t - lgm->tunnels, t->vni, t->vni);
850 format (s, " fibs: encap %d, decap %d decap next %U\n",
851 t->encap_fib_index, t->decap_fib_index, format_decap_next,
852 t->decap_next_index);
853 s = format (s, " lisp ver %d ", (t->ver_res >> 6));
855 #define _(n,v) if (t->flags & v) s = format (s, "%s-bit ", #n);
856 foreach_lisp_gpe_flag_bit;
859 s = format (s, "next_protocol %d ver_res %x res %x\n",
860 t->next_protocol, t->ver_res, t->res);
862 s = format (s, " locator-pairs:\n");
863 vec_foreach (lp, t->locator_pairs)
865 s = format (s, " local: %U remote: %U weight %d\n",
866 format_ip_address, &lp->lcl_loc, format_ip_address,
867 &lp->rmt_loc, lp->weight);
870 s = format (s, " active sub-tunnels:\n");
871 vec_foreach (nstw, t->norm_sub_tunnel_weights)
873 lp = vec_elt_at_index (t->locator_pairs, nstw->sub_tunnel_index);
874 s = format (s, " local: %U remote: %U weight %d\n", format_ip_address,
875 &lp->lcl_loc, format_ip_address, &lp->rmt_loc, nstw->weight);
880 /** CLI command to show LISP-GPE tunnels. */
881 static clib_error_t *
882 show_lisp_gpe_tunnel_command_fn (vlib_main_t * vm,
883 unformat_input_t * input,
884 vlib_cli_command_t * cmd)
886 lisp_gpe_main_t *lgm = &lisp_gpe_main;
887 lisp_gpe_tunnel_t *t;
889 if (pool_elts (lgm->tunnels) == 0)
890 vlib_cli_output (vm, "No lisp-gpe tunnels configured...");
893 pool_foreach (t, lgm->tunnels,
895 vlib_cli_output (vm, "%U", format_lisp_gpe_tunnel, t);
903 VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) =
905 .path = "show lisp gpe tunnel",
906 .function = show_lisp_gpe_tunnel_command_fn,
910 /** Check if LISP-GPE is enabled. */
912 vnet_lisp_gpe_enable_disable_status (void)
914 lisp_gpe_main_t *lgm = &lisp_gpe_main;
919 /** Enable/disable LISP-GPE. */
921 vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a)
923 lisp_gpe_main_t *lgm = &lisp_gpe_main;
924 vnet_main_t *vnm = lgm->vnet_main;
928 /* add lgpe_ip4_lookup as possible next_node for ip4 lookup */
929 if (lgm->ip4_lookup_next_lgpe_ip4_lookup == ~0)
931 lgm->ip4_lookup_next_lgpe_ip4_lookup =
932 vlib_node_add_next (vnm->vlib_main, ip4_lookup_node.index,
933 lgpe_ip4_lookup_node.index);
935 /* add lgpe_ip6_lookup as possible next_node for ip6 lookup */
936 if (lgm->ip6_lookup_next_lgpe_ip6_lookup == ~0)
938 lgm->ip6_lookup_next_lgpe_ip6_lookup =
939 vlib_node_add_next (vnm->vlib_main, ip6_lookup_node.index,
940 lgpe_ip6_lookup_node.index);
944 /* ask cp to re-add ifaces and defaults */
951 CLIB_UNUSED (uword * val);
953 u32 *dp_tables = 0, *dp_table;
954 lisp_gpe_tunnel_key_t *tunnels = 0, *tunnel;
955 vnet_lisp_gpe_add_del_fwd_entry_args_t _at, *at = &_at;
956 vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
958 /* remove all tunnels */
961 mhash_foreach(tunnel, val, &lgm->lisp_gpe_tunnel_by_key, ({
962 vec_add1(tunnels, tunnel[0]);
966 vec_foreach (tunnel, tunnels)
968 memset (at, 0, sizeof (at[0]));
970 if (tunnel->rmt.type == GID_ADDR_IP_PREFIX)
972 gid_address_type (&at->rmt_eid) = GID_ADDR_IP_PREFIX;
973 ip_prefix_copy (&gid_address_ippref (&at->rmt_eid),
974 &tunnel->rmt.ippref);
978 gid_address_type (&at->rmt_eid) = GID_ADDR_MAC;
979 mac_copy (&gid_address_mac (&at->rmt_eid), &tunnel->rmt.mac);
981 vnet_lisp_gpe_add_del_fwd_entry (at, 0);
985 /* disable all l3 ifaces */
988 hash_foreach_pair(p, lgm->l3_ifaces.hw_if_index_by_dp_table, ({
989 vec_add1(dp_tables, p->key);
993 vec_foreach (dp_table, dp_tables)
996 ai->table_id = dp_table[0];
999 /* disables interface and removes defaults */
1000 vnet_lisp_gpe_add_del_iface (ai, 0);
1003 /* disable all l2 ifaces */
1004 _vec_len (dp_tables) = 0;
1007 hash_foreach_pair(p, lgm->l2_ifaces.hw_if_index_by_dp_table, ({
1008 vec_add1(dp_tables, p->key);
1012 vec_foreach (dp_table, dp_tables)
1015 ai->bd_id = dp_table[0];
1018 /* disables interface and removes defaults */
1019 vnet_lisp_gpe_add_del_iface (ai, 0);
1022 vec_free (dp_tables);
1029 /** CLI command to enable/disable LISP-GPE. */
1030 static clib_error_t *
1031 lisp_gpe_enable_disable_command_fn (vlib_main_t * vm,
1032 unformat_input_t * input,
1033 vlib_cli_command_t * cmd)
1035 unformat_input_t _line_input, *line_input = &_line_input;
1037 vnet_lisp_gpe_enable_disable_args_t _a, *a = &_a;
1039 /* Get a line of input. */
1040 if (!unformat_user (input, unformat_line_input, line_input))
1043 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
1045 if (unformat (line_input, "enable"))
1047 else if (unformat (line_input, "disable"))
1051 return clib_error_return (0, "parse error: '%U'",
1052 format_unformat_error, line_input);
1056 return vnet_lisp_gpe_enable_disable (a);
1060 VLIB_CLI_COMMAND (enable_disable_lisp_gpe_command, static) = {
1062 .short_help = "lisp gpe [enable|disable]",
1063 .function = lisp_gpe_enable_disable_command_fn,
1067 /** CLI command to show LISP-GPE interfaces. */
1068 static clib_error_t *
1069 lisp_show_iface_command_fn (vlib_main_t * vm,
1070 unformat_input_t * input,
1071 vlib_cli_command_t * cmd)
1073 lisp_gpe_main_t *lgm = &lisp_gpe_main;
1076 vlib_cli_output (vm, "%=10s%=12s", "vrf", "hw_if_index");
1079 hash_foreach_pair (p, lgm->l3_ifaces.hw_if_index_by_dp_table, ({
1080 vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
1084 if (0 != lgm->l2_ifaces.hw_if_index_by_dp_table)
1086 vlib_cli_output (vm, "%=10s%=12s", "bd_id", "hw_if_index");
1088 hash_foreach_pair (p, lgm->l2_ifaces.hw_if_index_by_dp_table, ({
1089 vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
1097 VLIB_CLI_COMMAND (lisp_show_iface_command) = {
1098 .path = "show lisp gpe interface",
1099 .short_help = "show lisp gpe interface",
1100 .function = lisp_show_iface_command_fn,
1104 /** Format LISP-GPE status. */
1106 format_vnet_lisp_gpe_status (u8 * s, va_list * args)
1108 lisp_gpe_main_t *lgm = &lisp_gpe_main;
1109 return format (s, "%s", lgm->is_en ? "enabled" : "disabled");
1112 /** LISP-GPE init function. */
1114 lisp_gpe_init (vlib_main_t * vm)
1116 lisp_gpe_main_t *lgm = &lisp_gpe_main;
1117 clib_error_t *error = 0;
1119 if ((error = vlib_call_init_function (vm, ip_main_init)))
1122 if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
1125 lgm->vnet_main = vnet_get_main ();
1126 lgm->vlib_main = vm;
1127 lgm->im4 = &ip4_main;
1128 lgm->im6 = &ip6_main;
1129 lgm->lm4 = &ip4_main.lookup_main;
1130 lgm->lm6 = &ip6_main.lookup_main;
1131 lgm->ip4_lookup_next_lgpe_ip4_lookup = ~0;
1132 lgm->ip6_lookup_next_lgpe_ip6_lookup = ~0;
1134 mhash_init (&lgm->lisp_gpe_tunnel_by_key, sizeof (uword),
1135 sizeof (lisp_gpe_tunnel_key_t));
1139 udp_register_dst_port (vm, UDP_DST_PORT_lisp_gpe,
1140 lisp_gpe_ip4_input_node.index, 1 /* is_ip4 */ );
1141 udp_register_dst_port (vm, UDP_DST_PORT_lisp_gpe6,
1142 lisp_gpe_ip6_input_node.index, 0 /* is_ip4 */ );
1146 VLIB_INIT_FUNCTION (lisp_gpe_init);
1149 * fd.io coding-style-patch-verification: ON
1152 * eval: (c-set-style "gnu")