2 * gbp.h : Group Based Policy
4 * Copyright (c) 2018 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:
9 * http://www.apache.org/licenses/LICENSE-2.0
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.
18 #include <plugins/gbp/gbp_endpoint.h>
19 #include <plugins/gbp/gbp_endpoint_group.h>
20 #include <plugins/gbp/gbp_itf.h>
21 #include <plugins/gbp/gbp_scanner.h>
22 #include <plugins/gbp/gbp_bridge_domain.h>
23 #include <plugins/gbp/gbp_route_domain.h>
24 #include <plugins/gbp/gbp_policy_dpo.h>
25 #include <plugins/gbp/gbp_vxlan.h>
27 #include <vnet/ethernet/arp.h>
28 #include <vnet/l2/l2_input.h>
29 #include <vnet/l2/l2_output.h>
30 #include <vnet/l2/feat_bitmap.h>
31 #include <vnet/l2/l2_fib.h>
32 #include <vnet/fib/fib_table.h>
33 #include <vnet/ip/ip_neighbor.h>
35 static const char *gbp_endpoint_attr_names[] = GBP_ENDPOINT_ATTR_NAMES;
40 gbp_ep_db_t gbp_ep_db;
42 vlib_log_class_t gbp_ep_logger;
44 #define GBP_ENDPOINT_DBG(...) \
45 vlib_log_debug (gbp_ep_logger, __VA_ARGS__);
47 #define GBP_ENDPOINT_INFO(...) \
48 vlib_log_notice (gbp_ep_logger, __VA_ARGS__);
51 * GBP Endpoint inactive timeout (in seconds)
52 * If a dynamically learned Endpoint has not been heard from in this
53 * amount of time it is considered inactive and discarded
55 static u32 GBP_ENDPOINT_INACTIVE_TIME = 30;
58 * Pool of GBP endpoints
60 gbp_endpoint_t *gbp_endpoint_pool;
63 * A count of the number of dynamic entries
65 static u32 gbp_n_learnt_endpoints;
67 #define FOR_EACH_GBP_ENDPOINT_ATTR(_item) \
68 for (_item = GBP_ENDPOINT_ATTR_FIRST; \
69 _item < GBP_ENDPOINT_ATTR_LAST; \
73 format_gbp_endpoint_flags (u8 * s, va_list * args)
75 gbp_endpoint_attr_t attr;
76 gbp_endpoint_flags_t flags = va_arg (*args, gbp_endpoint_flags_t);
78 FOR_EACH_GBP_ENDPOINT_ATTR (attr)
80 if ((1 << attr) & flags)
82 s = format (s, "%s,", gbp_endpoint_attr_names[attr]);
90 gbp_endpoint_is_remote (const gbp_endpoint_t * ge)
92 return (ge->ge_flags & GBP_ENDPOINT_FLAG_REMOTE);
96 gbp_endpoint_extract_key_mac_itf (const clib_bihash_kv_16_8_t * key,
97 mac_address_t * mac, u32 * sw_if_index)
99 mac_address_from_u64 (key->key[0], mac);
100 *sw_if_index = key->key[1];
104 gbp_endpoint_extract_key_ip_itf (const clib_bihash_kv_24_8_t * key,
105 ip46_address_t * ip, u32 * sw_if_index)
107 ip->as_u64[0] = key->key[0];
108 ip->as_u64[1] = key->key[1];
109 *sw_if_index = key->key[2];
113 gbp_endpoint_find_ip (const ip46_address_t * ip, u32 fib_index)
115 clib_bihash_kv_24_8_t key, value;
118 gbp_endpoint_mk_key_ip (ip, fib_index, &key);
120 rv = clib_bihash_search_24_8 (&gbp_ep_db.ged_by_ip_rd, &key, &value);
125 return (gbp_endpoint_get (value.value));
129 gbp_endpoint_add_itf (u32 sw_if_index, index_t gei)
131 vec_validate_init_empty (gbp_ep_db.ged_by_sw_if_index, sw_if_index, ~0);
133 gbp_ep_db.ged_by_sw_if_index[sw_if_index] = gei;
137 gbp_endpoint_add_mac (const mac_address_t * mac, u32 bd_index, index_t gei)
139 clib_bihash_kv_16_8_t key;
142 gbp_endpoint_mk_key_mac (mac->bytes, bd_index, &key);
145 rv = clib_bihash_add_del_16_8 (&gbp_ep_db.ged_by_mac_bd, &key, 1);
152 gbp_endpoint_add_ip (const ip46_address_t * ip, u32 fib_index, index_t gei)
154 clib_bihash_kv_24_8_t key;
157 gbp_endpoint_mk_key_ip (ip, fib_index, &key);
160 rv = clib_bihash_add_del_24_8 (&gbp_ep_db.ged_by_ip_rd, &key, 1);
166 gbp_endpoint_del_mac (const mac_address_t * mac, u32 bd_index)
168 clib_bihash_kv_16_8_t key;
170 gbp_endpoint_mk_key_mac (mac->bytes, bd_index, &key);
172 clib_bihash_add_del_16_8 (&gbp_ep_db.ged_by_mac_bd, &key, 0);
176 gbp_endpoint_del_ip (const ip46_address_t * ip, u32 fib_index)
178 clib_bihash_kv_24_8_t key;
180 gbp_endpoint_mk_key_ip (ip, fib_index, &key);
182 clib_bihash_add_del_24_8 (&gbp_ep_db.ged_by_ip_rd, &key, 0);
186 gbp_endpoint_index (const gbp_endpoint_t * ge)
188 return (ge - gbp_endpoint_pool);
192 ip46_address_get_type (const ip46_address_t * a)
194 return (ip46_address_is_ip4 (a) ? IP46_TYPE_IP4 : IP46_TYPE_IP6);
198 ip46_address_get_len (const ip46_address_t * a)
200 return (ip46_address_is_ip4 (a) ? 32 : 128);
203 static gbp_endpoint_t *
204 gbp_endpoint_alloc (epg_id_t epg_id,
205 index_t ggi, u32 sw_if_index, gbp_endpoint_flags_t flags,
206 const ip46_address_t * tun_src,
207 const ip46_address_t * tun_dst)
211 pool_get_zero (gbp_endpoint_pool, ge);
214 ge->ge_epg_id = epg_id;
215 ge->ge_flags = flags;
216 ge->ge_sw_if_index = sw_if_index;
217 ge->ge_last_time = vlib_time_now (vlib_get_main ());
219 gbp_endpoint_group_find_and_lock (epg_id);
221 if (gbp_endpoint_is_remote (ge))
224 ip46_address_copy (&ge->tun.ge_src, tun_src);
226 ip46_address_copy (&ge->tun.ge_dst, tun_dst);
229 * the input interface may be the parent GBP-vxlan interface,
230 * create a child vlxan-gbp tunnel and use that as the endpoint's
233 switch (gbp_vxlan_tunnel_get_type (sw_if_index))
235 case GBP_VXLAN_TEMPLATE_TUNNEL:
236 ge->tun.ge_parent_sw_if_index = sw_if_index;
238 gbp_vxlan_tunnel_clone_and_lock (sw_if_index, tun_src, tun_dst);
240 case VXLAN_GBP_TUNNEL:
241 ge->tun.ge_parent_sw_if_index =
242 vxlan_gbp_tunnel_get_parent (sw_if_index);
243 ge->ge_sw_if_index = sw_if_index;
244 vxlan_gbp_tunnel_lock (ge->ge_sw_if_index);
253 gbp_endpoint_update (u32 sw_if_index,
254 const ip46_address_t * ips,
255 const mac_address_t * mac,
257 gbp_endpoint_flags_t flags,
258 const ip46_address_t * tun_src,
259 const ip46_address_t * tun_dst, u32 * handle)
261 gbp_endpoint_group_t *gg;
265 if (~0 == sw_if_index)
266 return (VNET_API_ERROR_INVALID_SW_IF_INDEX);
269 ggi = gbp_endpoint_group_find_and_lock (epg_id);
271 if (INDEX_INVALID == ggi)
272 return (VNET_API_ERROR_NO_SUCH_ENTRY);
274 gg = gbp_endpoint_group_get (ggi);
279 if (NULL != mac && !mac_address_is_zero (mac))
282 * find an existing endpoint matching one of the key types
284 ge = gbp_endpoint_find_mac (mac->bytes, gg->gg_bd_index);
290 ge = gbp_endpoint_alloc (epg_id, ggi, sw_if_index, flags,
292 gei = gbp_endpoint_index (ge);
293 mac_address_copy (&ge->ge_mac, mac);
295 ge->ge_itf = gbp_itf_add_and_lock (ge->ge_sw_if_index,
298 gbp_itf_set_l2_input_feature (ge->ge_itf, gei,
299 L2INPUT_FEAT_GBP_FWD);
301 if (gbp_endpoint_is_remote (ge))
303 gbp_itf_set_l2_output_feature (ge->ge_itf, gei,
304 L2OUTPUT_FEAT_GBP_POLICY_MAC);
308 gbp_endpoint_add_itf (ge->ge_sw_if_index, gei);
309 gbp_itf_set_l2_output_feature (ge->ge_itf, gei,
310 L2OUTPUT_FEAT_GBP_POLICY_PORT);
313 gbp_endpoint_add_mac (mac, gg->gg_bd_index, gei);
315 l2fib_add_entry (mac->bytes, gg->gg_bd_index, ge->ge_sw_if_index,
316 L2FIB_ENTRY_RESULT_FLAG_STATIC);
321 * update existing entry..
323 ge->ge_flags = flags;
324 gei = gbp_endpoint_index (ge);
332 if (NULL != ips && !ip46_address_is_zero (ips))
334 const ip46_address_t *ip;
335 fib_protocol_t fproto;
336 gbp_endpoint_t *l3_ge;
340 * look for a matching EP by any of the address
341 * An EP's IP addresses cannot change so we can search based on
344 fproto = fib_proto_from_ip46 (ip46_address_get_type (&ips[0]));
346 l3_ge = gbp_endpoint_find_ip (&ips[0],
347 gbp_endpoint_group_get_fib_index (gg,
353 ge = gbp_endpoint_alloc (epg_id, ggi, sw_if_index, flags,
355 ge->ge_itf = gbp_itf_add_and_lock (sw_if_index, ~0);
359 gei = gbp_endpoint_index (ge);
365 ge->ge_flags = flags;
366 gei = gbp_endpoint_index (ge);
370 gei = gbp_endpoint_index (ge);
372 vec_validate (ge->ge_adjs, vec_len (ips) - 1);
374 vec_foreach_index (ii, ge->ge_ips)
376 ethernet_header_t *eth;
382 ip = &ge->ge_ips[ii];
383 ip_type = ip46_address_get_type (ip);
384 fproto = fib_proto_from_ip46 (ip_type);
386 bd_add_del_ip_mac (gg->gg_bd_index, ip_type, ip, &ge->ge_mac, 1);
388 // FIXME - check error
389 gbp_endpoint_add_ip (ip,
390 gbp_endpoint_group_get_fib_index (gg, fproto),
394 * add a host route via the EPG's BVI we need this because the
395 * adj fib does not install, due to cover refinement check, since
396 * the BVI's prefix is /32
400 .fp_len = ip46_address_get_len (ip),
403 vec_validate (rewrite, sizeof (*eth) - 1);
404 eth = (ethernet_header_t *) rewrite;
406 eth->type = clib_host_to_net_u16 ((fproto == FIB_PROTOCOL_IP4 ?
410 if (gbp_endpoint_is_remote (ge))
413 * for dynamic EPs we msut add the IP adjacency via the learned
414 * tunnel since the BD will not contain the EP's MAC since it was
415 * L3 learned. The dst MAC address used is the 'BD's MAC'.
417 ip_sw_if_index = ge->ge_sw_if_index;
419 mac_address_to_bytes (gbp_route_domain_get_local_mac (),
421 mac_address_to_bytes (gbp_route_domain_get_remote_mac (),
427 * for the static EPs we add the IP adjacency via the BVI
428 * knowing that the BD has the MAC address to route to and
429 * that policy will be applied on egress to the EP's port
431 ip_sw_if_index = gbp_endpoint_group_get_bvi (gg);
433 clib_memcpy (eth->src_address,
434 vnet_sw_interface_get_hw_address (vnet_get_main (),
436 sizeof (eth->src_address));
437 mac_address_to_bytes (&ge->ge_mac, eth->dst_address);
440 fib_table_entry_path_add
441 (gbp_endpoint_group_get_fib_index (gg, fproto),
442 &pfx, FIB_SOURCE_PLUGIN_LOW,
444 fib_proto_to_dpo (fproto), ip, ip_sw_if_index,
445 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
447 ge->ge_adjs[ii] = adj_nbr_add_or_lock_w_rewrite (fproto,
453 if (gbp_endpoint_is_remote (ge))
455 dpo_id_t policy_dpo = DPO_INVALID;
458 * interpose a policy DPO from the endpoint so that policy
461 gbp_policy_dpo_add_or_lock (fib_proto_to_dpo (fproto),
462 gg->gg_id, ~0, &policy_dpo);
464 fib_table_entry_special_dpo_add
465 (gbp_endpoint_group_get_fib_index (gg, fproto),
467 FIB_SOURCE_PLUGIN_HI, FIB_ENTRY_FLAG_INTERPOSE, &policy_dpo);
471 * send a gratuitous ARP on the EPG's uplink. this is done so
472 * that if this EP has moved from some other place in the
473 * 'fabric', upstream devices are informed
475 if (!(gbp_endpoint_is_remote (ge)) && ~0 != gg->gg_uplink_sw_if_index)
477 gbp_endpoint_add_itf (sw_if_index, gei);
478 if (ip46_address_is_ip4 (ip))
479 send_ip4_garp_w_addr (vlib_get_main (),
480 &ip->ip4, gg->gg_uplink_sw_if_index);
482 send_ip6_na_w_addr (vlib_get_main (),
483 &ip->ip6, gg->gg_uplink_sw_if_index);
492 * count the number of dynamic entries and kick off the scanner
493 * process is this is our first.
495 if (gbp_endpoint_is_remote (ge))
497 gbp_n_learnt_endpoints++;
499 if (1 == gbp_n_learnt_endpoints)
501 vlib_process_signal_event (vlib_get_main (),
502 gbp_scanner_node.index,
503 GBP_ENDPOINT_SCAN_START, 0);
509 * non-remote endpoints (i.e. those not arriving on iVXLAN
510 * tunnels) need to be classifed based on the the input interface.
511 * We enable the GBP-FWD feature only is the group has an uplink
512 * interface (on which the GBP-FWD feature would send UU traffic).
514 l2input_feat_masks_t feats = L2INPUT_FEAT_GBP_SRC_CLASSIFY;
516 if (~0 != gg->gg_uplink_sw_if_index)
517 feats |= L2INPUT_FEAT_GBP_FWD;
518 gbp_itf_set_l2_input_feature (ge->ge_itf, gbp_endpoint_index (ge),
524 *handle = (ge - gbp_endpoint_pool);
526 gbp_endpoint_group_unlock (ggi);
527 GBP_ENDPOINT_INFO ("update: %U", format_gbp_endpoint, gei);
533 gbp_endpoint_delete (index_t gei)
535 gbp_endpoint_group_t *gg;
538 if (pool_is_free_index (gbp_endpoint_pool, gei))
541 GBP_ENDPOINT_INFO ("delete: %U", format_gbp_endpoint, gei);
543 ge = gbp_endpoint_get (gei);
544 gg = gbp_endpoint_group_get (ge->ge_epg);
546 gbp_endpoint_del_mac (&ge->ge_mac, gg->gg_bd_index);
547 l2fib_del_entry (ge->ge_mac.bytes, gg->gg_bd_index, ge->ge_sw_if_index);
548 gbp_itf_set_l2_input_feature (ge->ge_itf, gei, (L2INPUT_FEAT_NONE));
549 gbp_itf_set_l2_output_feature (ge->ge_itf, gei, L2OUTPUT_FEAT_NONE);
551 if (NULL != ge->ge_ips)
553 const ip46_address_t *ip;
556 vec_foreach (ai, ge->ge_adjs)
560 vec_foreach (ip, ge->ge_ips)
562 fib_protocol_t fproto;
565 ip_type = ip46_address_get_type (ip);
566 fproto = fib_proto_from_ip46 (ip_type);
568 gbp_endpoint_del_ip (ip,
569 gbp_endpoint_group_get_fib_index (gg, fproto));
571 bd_add_del_ip_mac (gg->gg_bd_index, ip_type, ip, &ge->ge_mac, 0);
574 * remove a host route via the EPG's BVI
578 .fp_len = ip46_address_get_len (ip),
582 if (gbp_endpoint_is_remote (ge))
584 fib_table_entry_special_remove
585 (gbp_endpoint_group_get_fib_index (gg, fproto),
586 &pfx, FIB_SOURCE_PLUGIN_HI);
589 fib_table_entry_path_remove
590 (gbp_endpoint_group_get_fib_index (gg, fproto),
591 &pfx, FIB_SOURCE_PLUGIN_LOW,
592 fib_proto_to_dpo (fproto), ip,
593 (gbp_endpoint_is_remote (ge) ?
595 gbp_endpoint_group_get_bvi (gg)),
596 ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
600 if (ge->ge_flags & GBP_ENDPOINT_FLAG_LEARNT)
602 gbp_n_learnt_endpoints--;
604 if (0 == gbp_n_learnt_endpoints)
606 vlib_process_signal_event (vlib_get_main (),
607 gbp_scanner_node.index,
608 GBP_ENDPOINT_SCAN_STOP, 0);
612 gbp_itf_unlock (ge->ge_itf);
613 if (gbp_endpoint_is_remote (ge))
615 vxlan_gbp_tunnel_unlock (ge->ge_sw_if_index);
617 gbp_endpoint_group_unlock (ge->ge_epg);
618 pool_put (gbp_endpoint_pool, ge);
621 typedef struct gbp_endpoint_flush_ctx_t_
625 } gbp_endpoint_flush_ctx_t;
628 gbp_endpoint_flush_cb (index_t gei, void *args)
630 gbp_endpoint_flush_ctx_t *ctx = args;
633 ge = gbp_endpoint_get (gei);
635 if (gbp_endpoint_is_remote (ge) &&
636 ctx->sw_if_index == ge->tun.ge_parent_sw_if_index)
638 vec_add1 (ctx->geis, gei);
641 return (WALK_CONTINUE);
645 * remove all learnt endpoints using the interface
648 gbp_endpoint_flush (u32 sw_if_index)
650 gbp_endpoint_flush_ctx_t ctx = {
651 .sw_if_index = sw_if_index,
655 gbp_endpoint_walk (gbp_endpoint_flush_cb, &ctx);
657 vec_foreach (gei, ctx.geis)
659 gbp_endpoint_delete (*gei);
666 gbp_endpoint_walk (gbp_endpoint_cb_t cb, void *ctx)
671 pool_foreach_index(index, gbp_endpoint_pool,
679 static clib_error_t *
680 gbp_endpoint_cli (vlib_main_t * vm,
681 unformat_input_t * input, vlib_cli_command_t * cmd)
683 ip46_address_t ip = ip46_address_initializer, *ips = NULL;
684 mac_address_t mac = ZERO_MAC_ADDRESS;
685 vnet_main_t *vnm = vnet_get_main ();
686 u32 epg_id = EPG_INVALID;
687 u32 handle = INDEX_INVALID;
688 u32 sw_if_index = ~0;
692 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
694 ip46_address_reset (&ip);
696 if (unformat (input, "%U", unformat_vnet_sw_interface,
699 else if (unformat (input, "add"))
701 else if (unformat (input, "del"))
703 else if (unformat (input, "epg %d", &epg_id))
705 else if (unformat (input, "handle %d", &handle))
707 else if (unformat (input, "ip %U", unformat_ip4_address, &ip.ip4))
709 else if (unformat (input, "ip %U", unformat_ip6_address, &ip.ip6))
711 else if (unformat (input, "mac %U", unformat_mac_address, &mac))
719 if (~0 == sw_if_index)
720 return clib_error_return (0, "interface must be specified");
721 if (EPG_INVALID == epg_id)
722 return clib_error_return (0, "EPG-ID must be specified");
725 gbp_endpoint_update (sw_if_index, ips, &mac, epg_id,
726 GBP_ENDPOINT_FLAG_NONE, NULL, NULL, &handle);
729 return clib_error_return (0, "GBP Endpoint update returned %d", rv);
731 vlib_cli_output (vm, "handle %d\n", handle);
735 if (INDEX_INVALID == handle)
736 return clib_error_return (0, "handle must be specified");
738 gbp_endpoint_delete (handle);
748 * Configure a GBP Endpoint
751 * @cliexstart{set gbp endpoint [del] <interface> epg <ID> ip <IP>}
755 VLIB_CLI_COMMAND (gbp_endpoint_cli_node, static) = {
756 .path = "gbp endpoint",
757 .short_help = "gbp endpoint [del] <interface> epg <ID> ip <IP> mac <MAC>",
758 .function = gbp_endpoint_cli,
763 format_gbp_endpoint (u8 * s, va_list * args)
765 index_t gei = va_arg (*args, index_t);
766 const ip46_address_t *ip;
769 ge = gbp_endpoint_get (gei);
771 s = format (s, "[@%d] ", gei);
772 s = format (s, "IPs:[");
774 vec_foreach (ip, ge->ge_ips)
776 s = format (s, "%U, ", format_ip46_address, ip, IP46_TYPE_ANY);
780 s = format (s, " MAC:%U", format_mac_address_t, &ge->ge_mac);
781 s = format (s, " EPG-ID:%d", ge->ge_epg_id);
782 if (GBP_ENDPOINT_FLAG_NONE != ge->ge_flags)
784 s = format (s, " flags:%U", format_gbp_endpoint_flags, ge->ge_flags);
787 s = format (s, " itf:[%U]", format_gbp_itf, ge->ge_itf);
788 s = format (s, " last-time:[%f]", ge->ge_last_time);
794 gbp_endpoint_show_one (index_t gei, void *ctx)
799 vlib_cli_output (vm, " %U", format_gbp_endpoint, gei);
801 return (WALK_CONTINUE);
805 gbp_endpoint_walk_ip_itf (const clib_bihash_kv_24_8_t * kvp, void *arg)
813 gbp_endpoint_extract_key_ip_itf (kvp, &ip, &sw_if_index);
815 vlib_cli_output (vm, " {%U, %U} -> %d",
816 format_ip46_address, &ip, IP46_TYPE_ANY,
817 format_vnet_sw_if_index_name, vnet_get_main (),
818 sw_if_index, kvp->value);
822 gbp_endpoint_walk_mac_itf (const clib_bihash_kv_16_8_t * kvp, void *arg)
830 gbp_endpoint_extract_key_mac_itf (kvp, &mac, &sw_if_index);
832 vlib_cli_output (vm, " {%U, %U} -> %d",
833 format_mac_address_t, &mac,
834 format_vnet_sw_if_index_name, vnet_get_main (),
835 sw_if_index, kvp->value);
838 static clib_error_t *
839 gbp_endpoint_show (vlib_main_t * vm,
840 unformat_input_t * input, vlib_cli_command_t * cmd)
842 u32 show_dbs, handle;
844 handle = INDEX_INVALID;
847 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
849 if (unformat (input, "%d", &handle))
851 else if (unformat (input, "db"))
857 if (INDEX_INVALID != handle)
859 vlib_cli_output (vm, "%U", format_gbp_endpoint, handle);
863 vlib_cli_output (vm, "\nDatabases:");
864 clib_bihash_foreach_key_value_pair_24_8 (&gbp_ep_db.ged_by_ip_rd,
865 gbp_endpoint_walk_ip_itf, vm);
866 clib_bihash_foreach_key_value_pair_16_8
867 (&gbp_ep_db.ged_by_mac_bd, gbp_endpoint_walk_mac_itf, vm);
871 vlib_cli_output (vm, "Endpoints:");
872 gbp_endpoint_walk (gbp_endpoint_show_one, vm);
879 * Show Group Based Policy Endpoints and derived information
882 * @cliexstart{show gbp endpoint}
886 VLIB_CLI_COMMAND (gbp_endpoint_show_node, static) = {
887 .path = "show gbp endpoint",
888 .short_help = "show gbp endpoint\n",
889 .function = gbp_endpoint_show,
894 gbp_endpoint_check (index_t gei, f64 start_time)
898 ge = gbp_endpoint_get (gei);
900 GBP_ENDPOINT_DBG ("scan at:%f -> %U", start_time, format_gbp_endpoint, gei);
902 if ((ge->ge_flags & GBP_ENDPOINT_FLAG_LEARNT) &&
903 ((start_time - ge->ge_last_time) > GBP_ENDPOINT_INACTIVE_TIME))
905 gbp_endpoint_delete (gei);
910 gbp_endpoint_scan_l2 (vlib_main_t * vm)
912 clib_bihash_16_8_t *gte_table = &gbp_ep_db.ged_by_mac_bd;
913 f64 last_start, start_time, delta_t;
917 last_start = start_time = vlib_time_now (vm);
919 for (i = 0; i < gte_table->nbuckets; i++)
921 clib_bihash_bucket_16_8_t *b;
922 clib_bihash_value_16_8_t *v;
924 /* allow no more than 20us without a pause */
925 delta_t = vlib_time_now (vm) - last_start;
928 /* suspend for 100 us */
929 vlib_process_suspend (vm, 100e-6);
930 last_start = vlib_time_now (vm);
933 b = >e_table->buckets[i];
936 v = clib_bihash_get_value_16_8 (gte_table, b->offset);
938 for (j = 0; j < (1 << b->log2_pages); j++)
940 for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
942 if (clib_bihash_is_free_16_8 (&v->kvp[k]))
945 gbp_endpoint_check (v->kvp[k].value, start_time);
948 * Note: we may have just freed the bucket's backing
949 * storage, so check right here...
962 gbp_endpoint_scan_l3 (vlib_main_t * vm)
964 clib_bihash_24_8_t *gte_table = &gbp_ep_db.ged_by_ip_rd;
965 f64 last_start, start_time, delta_t;
969 last_start = start_time = vlib_time_now (vm);
971 for (i = 0; i < gte_table->nbuckets; i++)
973 clib_bihash_bucket_24_8_t *b;
974 clib_bihash_value_24_8_t *v;
976 /* allow no more than 20us without a pause */
977 delta_t = vlib_time_now (vm) - last_start;
980 /* suspend for 100 us */
981 vlib_process_suspend (vm, 100e-6);
982 last_start = vlib_time_now (vm);
985 b = >e_table->buckets[i];
988 v = clib_bihash_get_value_24_8 (gte_table, b->offset);
990 for (j = 0; j < (1 << b->log2_pages); j++)
992 for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
994 if (clib_bihash_is_free_24_8 (&v->kvp[k]))
997 gbp_endpoint_check (v->kvp[k].value, start_time);
1000 * Note: we may have just freed the bucket's backing
1001 * storage, so check right here...
1014 gbp_endpoint_scan (vlib_main_t * vm)
1016 gbp_endpoint_scan_l2 (vm);
1017 gbp_endpoint_scan_l3 (vm);
1021 gbp_learn_set_inactive_threshold (u32 threshold)
1023 GBP_ENDPOINT_INACTIVE_TIME = threshold;
1027 gbp_endpoint_scan_threshold (void)
1029 return (GBP_ENDPOINT_INACTIVE_TIME);
1032 #define GBP_EP_HASH_NUM_BUCKETS (2 * 1024)
1033 #define GBP_EP_HASH_MEMORY_SIZE (1 << 20)
1035 static clib_error_t *
1036 gbp_endpoint_init (vlib_main_t * vm)
1038 clib_bihash_init_24_8 (&gbp_ep_db.ged_by_ip_rd,
1039 "GBP Endpoints - IP/RD",
1040 GBP_EP_HASH_NUM_BUCKETS, GBP_EP_HASH_MEMORY_SIZE);
1042 clib_bihash_init_16_8 (&gbp_ep_db.ged_by_mac_bd,
1043 "GBP Endpoints - MAC/BD",
1044 GBP_EP_HASH_NUM_BUCKETS, GBP_EP_HASH_MEMORY_SIZE);
1046 gbp_ep_logger = vlib_log_register_class ("gbp", "ep");
1051 VLIB_INIT_FUNCTION (gbp_endpoint_init);
1054 * fd.io coding-style-patch-verification: ON
1057 * eval: (c-set-style "gnu")