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.
16 #include <vnet/lisp-gpe/lisp_gpe.h>
17 #include <vppinfra/math.h>
19 lisp_gpe_main_t lisp_gpe_main;
22 lisp_gpe_rewrite (lisp_gpe_tunnel_t * t, lisp_gpe_sub_tunnel_t * st,
26 lisp_gpe_header_t *lisp0;
29 if (ip_addr_version (&lp->lcl_loc) == IP4)
32 ip4_udp_lisp_gpe_header_t *h0;
35 vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
37 h0 = (ip4_udp_lisp_gpe_header_t *) rw;
39 /* Fixed portion of the (outer) ip4 header */
41 ip0->ip_version_and_header_length = 0x45;
43 ip0->protocol = IP_PROTOCOL_UDP;
45 /* we fix up the ip4 header length and checksum after-the-fact */
46 ip_address_copy_addr (&ip0->src_address, &lp->lcl_loc);
47 ip_address_copy_addr (&ip0->dst_address, &lp->rmt_loc);
48 ip0->checksum = ip4_header_checksum (ip0);
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);
60 ip6_udp_lisp_gpe_header_t *h0;
63 vec_validate_aligned (rw, len - 1, CLIB_CACHE_LINE_BYTES);
65 h0 = (ip6_udp_lisp_gpe_header_t *) rw;
67 /* Fixed portion of the (outer) ip6 header */
69 ip0->ip_version_traffic_class_and_flow_label =
70 clib_host_to_net_u32 (0x6 << 28);
72 ip0->protocol = IP_PROTOCOL_UDP;
74 /* we fix up the ip6 header length after-the-fact */
75 ip_address_copy_addr (&ip0->src_address, &lp->lcl_loc);
76 ip_address_copy_addr (&ip0->dst_address, &lp->rmt_loc);
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);
86 lisp0->flags = t->flags;
87 lisp0->ver_res = t->ver_res;
89 lisp0->next_protocol = t->next_protocol;
90 lisp0->iid = clib_host_to_net_u32 (t->vni);
92 st->is_ip4 = ip_addr_version (&lp->lcl_loc) == IP4;
98 weight_cmp (normalized_sub_tunnel_weights_t * a,
99 normalized_sub_tunnel_weights_t * b)
101 int cmp = a->weight - b->weight;
103 ? a->sub_tunnel_index - b->sub_tunnel_index : (cmp > 0 ? -1 : 1));
106 /** Computes sub tunnel load balancing vector.
107 * Algorithm is identical to that used for building unequal-cost multipath
110 compute_sub_tunnels_balancing_vector (lisp_gpe_tunnel_t * t)
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;
115 lisp_gpe_sub_tunnel_t *sts = t->sub_tunnels;
118 /* Accept 1% error */
121 n_sts = vec_len (sts);
122 vec_validate (nsts, 2 * n_sts - 1);
125 for (i = 0; i < n_sts; i++)
127 /* Find total weight to normalize weights. */
128 sum_weight += sts[i].weight;
130 /* build normalized sub tunnels vector */
131 nsts[i].weight = sts[i].weight;
132 nsts[i].sub_tunnel_index = i;
143 /* Sort sub-tunnels by weight */
144 qsort (nsts, n_nsts, sizeof (u32), (void *) weight_cmp);
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;
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)
156 norm = n_nsts / sum_weight;
157 n_nsts_left = n_nsts;
158 for (i = 0; i < n_sts; i++)
160 f64 nf = nsts[n_sts + i].weight * norm;
161 word n = flt_round_nearest (nf);
163 n = n > n_nsts_left ? n_nsts_left : n;
165 error += fabs (nf - n);
169 nsts[0].weight += n_nsts_left;
171 /* Less than 5% average error per adjacency with this size adjacency block? */
172 if (error <= tolerance * n_nsts)
174 /* Truncate any next hops with zero weight. */
182 /* build load balancing vector */
183 vec_foreach (stp, nsts)
185 for (i = 0; i < stp[0].weight; i++)
186 vec_add1 (st_lbv, stp[0].sub_tunnel_index);
189 t->sub_tunnels_lbv = st_lbv;
190 t->sub_tunnels_lbv_count = n_nsts;
191 t->norm_sub_tunnel_weights = nsts;
195 create_sub_tunnels (lisp_gpe_main_t * lgm, lisp_gpe_tunnel_t * t)
197 lisp_gpe_sub_tunnel_t st;
198 locator_pair_t *lp = 0;
201 /* create sub-tunnels for all locator pairs */
202 for (i = 0; i < vec_len (t->locator_pairs); i++)
204 lp = &t->locator_pairs[i];
205 st.locator_pair_index = i;
206 st.parent_index = t - lgm->tunnels;
207 st.weight = lp->weight;
209 /* compute rewrite for sub-tunnel */
210 lisp_gpe_rewrite (t, &st, lp);
211 vec_add1 (t->sub_tunnels, st);
214 /* normalize weights and compute sub-tunnel load balancing vector */
215 compute_sub_tunnels_balancing_vector (t);
218 #define foreach_copy_field \
221 _(decap_next_index) \
226 add_del_ip_tunnel (vnet_lisp_gpe_add_del_fwd_entry_args_t * a, u8 is_l2,
229 lisp_gpe_main_t *lgm = &lisp_gpe_main;
230 lisp_gpe_tunnel_t *t = 0;
231 lisp_gpe_tunnel_key_t key;
232 lisp_gpe_sub_tunnel_t *stp = 0;
235 /* prepare tunnel key */
236 memset (&key, 0, sizeof (key));
238 /* fill in the key's remote eid */
240 ip_prefix_copy (&key.rmt.ippref, &gid_address_ippref (&a->rmt_eid));
242 mac_copy (&key.rmt.mac, &gid_address_mac (&a->rmt_eid));
244 key.vni = clib_host_to_net_u32 (a->vni);
246 p = mhash_get (&lgm->lisp_gpe_tunnel_by_key, &key);
250 /* adding a tunnel: tunnel must not already exist */
252 return VNET_API_ERROR_INVALID_VALUE;
254 if (a->decap_next_index >= LISP_GPE_INPUT_N_NEXT)
255 return VNET_API_ERROR_INVALID_DECAP_NEXT;
257 pool_get_aligned (lgm->tunnels, t, CLIB_CACHE_LINE_BYTES);
258 memset (t, 0, sizeof (*t));
260 /* copy from arg structure */
261 #define _(x) t->x = a->x;
265 t->locator_pairs = vec_dup (a->locator_pairs);
267 /* if vni is non-default */
269 t->flags = LISP_GPE_FLAGS_I;
271 /* work in lisp-gpe not legacy mode */
272 t->flags |= LISP_GPE_FLAGS_P;
276 t->next_protocol = ip_prefix_version (&key.rmt.ippref) == IP4 ?
277 LISP_GPE_NEXT_PROTO_IP4 : LISP_GPE_NEXT_PROTO_IP6;
279 t->next_protocol = LISP_GPE_NEXT_PROTO_ETHERNET;
281 /* build sub-tunnels for lowest priority locator-pairs */
283 create_sub_tunnels (lgm, t);
285 mhash_set (&lgm->lisp_gpe_tunnel_by_key, &key, t - lgm->tunnels, 0);
287 /* return tunnel index */
289 tun_index_res[0] = t - lgm->tunnels;
293 /* deleting a tunnel: tunnel must exist */
296 clib_warning ("Tunnel for eid %U doesn't exist!",
297 format_gid_address, &a->rmt_eid);
298 return VNET_API_ERROR_NO_SUCH_ENTRY;
301 t = pool_elt_at_index (lgm->tunnels, p[0]);
303 mhash_unset (&lgm->lisp_gpe_tunnel_by_key, &key, 0);
305 vec_foreach (stp, t->sub_tunnels)
307 vec_free (stp->rewrite);
309 vec_free (t->sub_tunnels);
310 vec_free (t->sub_tunnels_lbv);
311 vec_free (t->locator_pairs);
312 pool_put (lgm->tunnels, t);
319 build_ip_adjacency (lisp_gpe_main_t * lgm, ip_adjacency_t * adj, u32 table_id,
320 u32 vni, u32 tun_index, u32 n_sub_tun, u8 is_negative,
321 u8 action, u8 ip_ver)
323 uword *lookup_next_index, *lgpe_sw_if_index, *lnip;
325 memset (adj, 0, sizeof (adj[0]));
327 /* fill in lookup_next_index with a 'legal' value to avoid problems */
328 adj->lookup_next_index = (ip_ver == IP4) ?
329 lgm->ip4_lookup_next_lgpe_ip4_lookup :
330 lgm->ip6_lookup_next_lgpe_ip6_lookup;
332 /* positive mapping */
335 /* send packets that hit this adj to lisp-gpe interface output node in
337 lnip = (ip_ver == IP4) ?
338 lgm->lgpe_ip4_lookup_next_index_by_table_id :
339 lgm->lgpe_ip6_lookup_next_index_by_table_id;
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);
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);
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;
355 /* negative mapping */
358 adj->rewrite_header.sw_if_index = ~0;
359 adj->rewrite_header.next_index = ~0;
360 adj->if_address_index = tun_index;
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 */
369 case LISP_SEND_MAP_REQUEST:
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;
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);
389 add_del_ip_fwd_entry (lisp_gpe_main_t * lgm,
390 vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
392 ip_adjacency_t adj, *adjp;
393 lisp_gpe_tunnel_t *t;
394 u32 rv, tun_index = ~0, n_sub_tuns = 0;
395 ip_prefix_t *rmt_pref, *lcl_pref;
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);
402 /* add/del tunnel to tunnels pool and prepares rewrite */
403 if (0 != a->locator_pairs)
405 rv = add_del_ip_tunnel (a, 0 /* is_l2 */ , &tun_index);
408 clib_warning ("failed to build tunnel!");
413 t = pool_elt_at_index (lgm->tunnels, tun_index);
414 n_sub_tuns = t->sub_tunnels_lbv_count;
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);
422 /* add/delete route for eid */
423 rv |= ip_sd_fib_add_del_route (lgm, rmt_pref, lcl_pref, a->table_id, &adj,
428 clib_warning ("failed to insert route for tunnel!");
432 /* check that everything worked */
433 if (CLIB_DEBUG && a->is_add)
436 adj_index = ip_sd_fib_get_route (lgm, rmt_pref, lcl_pref, a->table_id);
437 ASSERT (adj_index != 0);
439 adjp = ip_get_adjacency ((ip_ver == IP4) ? lgm->lm4 : lgm->lm6,
442 ASSERT (adjp != 0 && adjp->if_address_index == tun_index);
449 make_mac_fib_key (BVT (clib_bihash_kv) * kv, u16 bd_index, u8 src_mac[6],
452 kv->key[0] = (((u64) bd_index) << 48) | mac_to_u64 (dst_mac);
453 kv->key[1] = mac_to_u64 (src_mac);
458 lisp_l2_fib_lookup (lisp_gpe_main_t * lgm, u16 bd_index, u8 src_mac[6],
462 BVT (clib_bihash_kv) kv, value;
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);
467 /* no match, try with src 0, catch all for dst */
471 rv = BV (clib_bihash_search_inline_2) (&lgm->l2_fib, &kv, &value);
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)
483 BVT (clib_bihash_kv) kv, value;
486 make_mac_fib_key (&kv, bd_index, src_mac, dst_mac);
488 if (BV (clib_bihash_search) (&lgm->l2_fib, &kv, &value) == 0)
489 old_val = value.value;
492 BV (clib_bihash_add_del) (&lgm->l2_fib, &kv, 0 /* is_add */ );
496 BV (clib_bihash_add_del) (&lgm->l2_fib, &kv, 1 /* is_add */ );
502 l2_fib_init (lisp_gpe_main_t * lgm)
504 BV (clib_bihash_init) (&lgm->l2_fib, "l2 fib",
505 1 << max_log2 (L2_FIB_DEFAULT_HASH_NUM_BUCKETS),
506 L2_FIB_DEFAULT_HASH_MEMORY_SIZE);
510 add_del_l2_fwd_entry (lisp_gpe_main_t * lgm,
511 vnet_lisp_gpe_add_del_fwd_entry_args_t * a)
515 bd_main_t *bdm = &bd_main;
519 rv = add_del_ip_tunnel (a, 1 /* is_l2 */ , &tun_index);
523 bd_indexp = hash_get (bdm->bd_index_by_bd_id, a->bd_id);
526 clib_warning ("bridge domain %d doesn't exist", a->bd_id);
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,
539 vnet_lisp_gpe_add_del_fwd_entry (vnet_lisp_gpe_add_del_fwd_entry_args_t * a,
542 lisp_gpe_main_t *lgm = &lisp_gpe_main;
545 if (vnet_lisp_gpe_enable_disable_status () == 0)
547 clib_warning ("LISP is disabled!");
548 return VNET_API_ERROR_LISP_DISABLED;
551 type = gid_address_type (&a->rmt_eid);
554 case GID_ADDR_IP_PREFIX:
555 return add_del_ip_fwd_entry (lgm, a);
557 return add_del_l2_fwd_entry (lgm, a);
559 clib_warning ("Forwarding entries for type %d not supported!", type);
564 static clib_error_t *
565 lisp_gpe_add_del_fwd_entry_command_fn (vlib_main_t * vm,
566 unformat_input_t * input,
567 vlib_cli_command_t * cmd)
569 unformat_input_t _line_input, *line_input = &_line_input;
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;
579 /* Get a line of input. */
580 if (!unformat_user (input, unformat_line_input, line_input))
583 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
585 if (unformat (line_input, "del"))
587 else if (unformat (line_input, "add"))
589 else if (unformat (line_input, "leid %U", unformat_gid_address, leid))
593 else if (unformat (line_input, "reid %U", unformat_gid_address, reid))
597 else if (unformat (line_input, "vni %u", &vni))
599 gid_address_vni (leid) = vni;
600 gid_address_vni (reid) = vni;
603 else if (unformat (line_input, "vrf %u", &vrf))
607 else if (unformat (line_input, "negative action %U",
608 unformat_negative_mapping_action, &action))
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))
620 vec_add1 (pairs, pair);
624 error = unformat_parse_error (line_input);
628 unformat_free (line_input);
630 if (!vni_set || !vrf_set)
632 error = clib_error_return (0, "vni and vrf must be set!");
638 error = clib_error_return (0, "remote eid must be set!");
646 error = clib_error_return (0, "no action set for negative tunnel!");
652 if (vec_len (pairs) == 0)
654 error = clib_error_return (0, "expected ip4/ip6 locators.");
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))
664 gid_address_ip_version (leid) = gid_address_ip_version (reid);
668 vnet_lisp_gpe_add_del_fwd_entry_args_t _a, *a = &_a;
669 memset (a, 0, sizeof (a[0]));
674 gid_address_copy (&a->lcl_eid, leid);
675 gid_address_copy (&a->rmt_eid, reid);
676 a->locator_pairs = pairs;
678 rv = vnet_lisp_gpe_add_del_fwd_entry (a, 0);
681 error = clib_error_return (0, "failed to %s gpe tunnel!",
682 is_add ? "add" : "delete");
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>]",
695 .function = lisp_gpe_add_del_fwd_entry_command_fn,
700 format_decap_next (u8 * s, va_list * args)
702 u32 next_index = va_arg (*args, u32);
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");
713 return format (s, "unknown %d", next_index);
719 format_lisp_gpe_tunnel (u8 * s, va_list * args)
721 lisp_gpe_tunnel_t *t = va_arg (*args, lisp_gpe_tunnel_t *);
722 lisp_gpe_main_t *lgm = vnet_lisp_gpe_get_main ();
723 locator_pair_t *lp = 0;
724 normalized_sub_tunnel_weights_t *nstw;
727 format (s, "tunnel %d vni %d (0x%x)\n", t - lgm->tunnels, t->vni, t->vni);
729 format (s, " fibs: encap %d, decap %d decap next %U\n",
730 t->encap_fib_index, t->decap_fib_index, format_decap_next,
731 t->decap_next_index);
732 s = format (s, " lisp ver %d ", (t->ver_res >> 6));
734 #define _(n,v) if (t->flags & v) s = format (s, "%s-bit ", #n);
735 foreach_lisp_gpe_flag_bit;
738 s = format (s, "next_protocol %d ver_res %x res %x\n",
739 t->next_protocol, t->ver_res, t->res);
741 s = format (s, " locator-pairs:\n");
742 vec_foreach (lp, t->locator_pairs)
744 s = format (s, " local: %U remote: %U weight %d\n",
745 format_ip_address, &lp->lcl_loc, format_ip_address,
746 &lp->rmt_loc, lp->weight);
749 s = format (s, " active sub-tunnels:\n");
750 vec_foreach (nstw, t->norm_sub_tunnel_weights)
752 lp = vec_elt_at_index (t->locator_pairs, nstw->sub_tunnel_index);
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);
759 static clib_error_t *
760 show_lisp_gpe_tunnel_command_fn (vlib_main_t * vm,
761 unformat_input_t * input,
762 vlib_cli_command_t * cmd)
764 lisp_gpe_main_t *lgm = &lisp_gpe_main;
765 lisp_gpe_tunnel_t *t;
767 if (pool_elts (lgm->tunnels) == 0)
768 vlib_cli_output (vm, "No lisp-gpe tunnels configured...");
771 pool_foreach (t, lgm->tunnels,
773 vlib_cli_output (vm, "%U", format_lisp_gpe_tunnel, t);
781 VLIB_CLI_COMMAND (show_lisp_gpe_tunnel_command, static) =
783 .path = "show lisp gpe tunnel",
784 .function = show_lisp_gpe_tunnel_command_fn,
789 vnet_lisp_gpe_enable_disable_status (void)
791 lisp_gpe_main_t *lgm = &lisp_gpe_main;
797 vnet_lisp_gpe_enable_disable (vnet_lisp_gpe_enable_disable_args_t * a)
799 lisp_gpe_main_t *lgm = &lisp_gpe_main;
800 vnet_main_t *vnm = lgm->vnet_main;
804 /* add lgpe_ip4_lookup as possible next_node for ip4 lookup */
805 if (lgm->ip4_lookup_next_lgpe_ip4_lookup == ~0)
807 lgm->ip4_lookup_next_lgpe_ip4_lookup =
808 vlib_node_add_next (vnm->vlib_main, ip4_lookup_node.index,
809 lgpe_ip4_lookup_node.index);
811 /* add lgpe_ip6_lookup as possible next_node for ip6 lookup */
812 if (lgm->ip6_lookup_next_lgpe_ip6_lookup == ~0)
814 lgm->ip6_lookup_next_lgpe_ip6_lookup =
815 vlib_node_add_next (vnm->vlib_main, ip6_lookup_node.index,
816 lgpe_ip6_lookup_node.index);
820 /* ask cp to re-add ifaces and defaults */
827 CLIB_UNUSED (uword * val);
829 u32 *dp_tables = 0, *dp_table;
830 lisp_gpe_tunnel_key_t *tunnels = 0, *tunnel;
831 vnet_lisp_gpe_add_del_fwd_entry_args_t _at, *at = &_at;
832 vnet_lisp_gpe_add_del_iface_args_t _ai, *ai = &_ai;
834 /* remove all tunnels */
837 mhash_foreach(tunnel, val, &lgm->lisp_gpe_tunnel_by_key, ({
838 vec_add1(tunnels, tunnel[0]);
842 vec_foreach (tunnel, tunnels)
844 memset (at, 0, sizeof (at[0]));
846 if (tunnel->rmt.type == GID_ADDR_IP_PREFIX)
848 gid_address_type (&at->rmt_eid) = GID_ADDR_IP_PREFIX;
849 ip_prefix_copy (&gid_address_ippref (&at->rmt_eid),
850 &tunnel->rmt.ippref);
854 gid_address_type (&at->rmt_eid) = GID_ADDR_MAC;
855 mac_copy (&gid_address_mac (&at->rmt_eid), &tunnel->rmt.mac);
857 vnet_lisp_gpe_add_del_fwd_entry (at, 0);
861 /* disable all l3 ifaces */
864 hash_foreach_pair(p, lgm->l3_ifaces.hw_if_index_by_dp_table, ({
865 vec_add1(dp_tables, p->key);
869 vec_foreach (dp_table, dp_tables)
872 ai->table_id = dp_table[0];
875 /* disables interface and removes defaults */
876 vnet_lisp_gpe_add_del_iface (ai, 0);
879 /* disable all l2 ifaces */
880 _vec_len (dp_tables) = 0;
883 hash_foreach_pair(p, lgm->l2_ifaces.hw_if_index_by_dp_table, ({
884 vec_add1(dp_tables, p->key);
888 vec_foreach (dp_table, dp_tables)
891 ai->bd_id = dp_table[0];
894 /* disables interface and removes defaults */
895 vnet_lisp_gpe_add_del_iface (ai, 0);
898 vec_free (dp_tables);
905 static clib_error_t *
906 lisp_gpe_enable_disable_command_fn (vlib_main_t * vm,
907 unformat_input_t * input,
908 vlib_cli_command_t * cmd)
910 unformat_input_t _line_input, *line_input = &_line_input;
912 vnet_lisp_gpe_enable_disable_args_t _a, *a = &_a;
914 /* Get a line of input. */
915 if (!unformat_user (input, unformat_line_input, line_input))
918 while (unformat_check_input (line_input) != UNFORMAT_END_OF_INPUT)
920 if (unformat (line_input, "enable"))
922 else if (unformat (line_input, "disable"))
926 return clib_error_return (0, "parse error: '%U'",
927 format_unformat_error, line_input);
931 return vnet_lisp_gpe_enable_disable (a);
935 VLIB_CLI_COMMAND (enable_disable_lisp_gpe_command, static) = {
937 .short_help = "lisp gpe [enable|disable]",
938 .function = lisp_gpe_enable_disable_command_fn,
942 static clib_error_t *
943 lisp_show_iface_command_fn (vlib_main_t * vm,
944 unformat_input_t * input,
945 vlib_cli_command_t * cmd)
947 lisp_gpe_main_t *lgm = &lisp_gpe_main;
950 vlib_cli_output (vm, "%=10s%=12s", "vrf", "hw_if_index");
953 hash_foreach_pair (p, lgm->l3_ifaces.hw_if_index_by_dp_table, ({
954 vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
958 if (0 != lgm->l2_ifaces.hw_if_index_by_dp_table)
960 vlib_cli_output (vm, "%=10s%=12s", "bd_id", "hw_if_index");
962 hash_foreach_pair (p, lgm->l2_ifaces.hw_if_index_by_dp_table, ({
963 vlib_cli_output (vm, "%=10d%=10d", p->key, p->value[0]);
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,
979 format_vnet_lisp_gpe_status (u8 * s, va_list * args)
981 lisp_gpe_main_t *lgm = &lisp_gpe_main;
982 return format (s, "%s", lgm->is_en ? "enabled" : "disabled");
986 lisp_gpe_init (vlib_main_t * vm)
988 lisp_gpe_main_t *lgm = &lisp_gpe_main;
989 clib_error_t *error = 0;
991 if ((error = vlib_call_init_function (vm, ip_main_init)))
994 if ((error = vlib_call_init_function (vm, ip4_lookup_init)))
997 lgm->vnet_main = vnet_get_main ();
999 lgm->im4 = &ip4_main;
1000 lgm->im6 = &ip6_main;
1001 lgm->lm4 = &ip4_main.lookup_main;
1002 lgm->lm6 = &ip6_main.lookup_main;
1003 lgm->ip4_lookup_next_lgpe_ip4_lookup = ~0;
1004 lgm->ip6_lookup_next_lgpe_ip6_lookup = ~0;
1006 mhash_init (&lgm->lisp_gpe_tunnel_by_key, sizeof (uword),
1007 sizeof (lisp_gpe_tunnel_key_t));
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 */ );
1018 VLIB_INIT_FUNCTION (lisp_gpe_init);
1021 * fd.io coding-style-patch-verification: ON
1024 * eval: (c-set-style "gnu")