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,
242 case VXLAN_GBP_TUNNEL:
243 ge->tun.ge_parent_sw_if_index =
244 vxlan_gbp_tunnel_get_parent (sw_if_index);
245 ge->ge_sw_if_index = sw_if_index;
246 vxlan_gbp_tunnel_lock (ge->ge_sw_if_index);
255 gbp_endpoint_update (u32 sw_if_index,
256 const ip46_address_t * ips,
257 const mac_address_t * mac,
259 gbp_endpoint_flags_t flags,
260 const ip46_address_t * tun_src,
261 const ip46_address_t * tun_dst, u32 * handle)
263 gbp_endpoint_group_t *gg;
267 if (~0 == sw_if_index)
268 return (VNET_API_ERROR_INVALID_SW_IF_INDEX);
271 ggi = gbp_endpoint_group_find_and_lock (epg_id);
273 if (INDEX_INVALID == ggi)
274 return (VNET_API_ERROR_NO_SUCH_ENTRY);
276 gg = gbp_endpoint_group_get (ggi);
281 if (NULL != mac && !mac_address_is_zero (mac))
284 * find an existing endpoint matching one of the key types
286 ge = gbp_endpoint_find_mac (mac->bytes, gg->gg_bd_index);
292 ge = gbp_endpoint_alloc (epg_id, ggi, sw_if_index, flags,
294 gei = gbp_endpoint_index (ge);
295 mac_address_copy (&ge->ge_mac, mac);
297 ge->ge_itf = gbp_itf_add_and_lock (ge->ge_sw_if_index,
300 gbp_itf_set_l2_input_feature (ge->ge_itf, gei,
301 L2INPUT_FEAT_GBP_FWD);
303 if (gbp_endpoint_is_remote (ge))
305 gbp_itf_set_l2_output_feature (ge->ge_itf, gei,
306 L2OUTPUT_FEAT_GBP_POLICY_MAC);
310 gbp_endpoint_add_itf (ge->ge_sw_if_index, gei);
311 gbp_itf_set_l2_output_feature (ge->ge_itf, gei,
312 L2OUTPUT_FEAT_GBP_POLICY_PORT);
315 gbp_endpoint_add_mac (mac, gg->gg_bd_index, gei);
317 l2fib_add_entry (mac->bytes, gg->gg_bd_index, ge->ge_sw_if_index,
318 L2FIB_ENTRY_RESULT_FLAG_STATIC);
323 * update existing entry..
325 ge->ge_flags = flags;
326 gei = gbp_endpoint_index (ge);
334 if (NULL != ips && !ip46_address_is_zero (ips))
336 const ip46_address_t *ip;
337 fib_protocol_t fproto;
338 gbp_endpoint_t *l3_ge;
342 * look for a matching EP by any of the address
343 * An EP's IP addresses cannot change so we can search based on
346 fproto = fib_proto_from_ip46 (ip46_address_get_type (&ips[0]));
348 l3_ge = gbp_endpoint_find_ip (&ips[0],
349 gbp_endpoint_group_get_fib_index (gg,
355 ge = gbp_endpoint_alloc (epg_id, ggi, sw_if_index, flags,
357 ge->ge_itf = gbp_itf_add_and_lock (sw_if_index, ~0);
367 ge->ge_flags = flags;
368 gei = gbp_endpoint_index (ge);
372 gei = gbp_endpoint_index (ge);
374 vec_validate (ge->ge_adjs, vec_len (ips) - 1);
376 vec_foreach_index (ii, ge->ge_ips)
378 ethernet_header_t *eth;
384 ip = &ge->ge_ips[ii];
385 ip_type = ip46_address_get_type (ip);
386 fproto = fib_proto_from_ip46 (ip_type);
388 bd_add_del_ip_mac (gg->gg_bd_index, ip_type, ip, &ge->ge_mac, 1);
390 // FIXME - check error
391 gbp_endpoint_add_ip (ip,
392 gbp_endpoint_group_get_fib_index (gg, fproto),
396 * add a host route via the EPG's BVI we need this because the
397 * adj fib does not install, due to cover refinement check, since
398 * the BVI's prefix is /32
402 .fp_len = ip46_address_get_len (ip),
405 vec_validate (rewrite, sizeof (*eth) - 1);
406 eth = (ethernet_header_t *) rewrite;
408 eth->type = clib_host_to_net_u16 ((fproto == FIB_PROTOCOL_IP4 ?
412 if (gbp_endpoint_is_remote (ge))
415 * for dynamic EPs we msut add the IP adjacency via the learned
416 * tunnel since the BD will not contain the EP's MAC since it was
417 * L3 learned. The dst MAC address used is the 'BD's MAC'.
419 ip_sw_if_index = ge->ge_sw_if_index;
421 mac_address_to_bytes (gbp_route_domain_get_local_mac (),
423 mac_address_to_bytes (gbp_route_domain_get_remote_mac (),
429 * for the static EPs we add the IP adjacency via the BVI
430 * knowing that the BD has the MAC address to route to and
431 * that policy will be applied on egress to the EP's port
433 ip_sw_if_index = gbp_endpoint_group_get_bvi (gg);
435 clib_memcpy (eth->src_address,
436 vnet_sw_interface_get_hw_address (vnet_get_main (),
438 sizeof (eth->src_address));
439 mac_address_to_bytes (&ge->ge_mac, eth->dst_address);
442 fib_table_entry_path_add
443 (gbp_endpoint_group_get_fib_index (gg, fproto),
444 &pfx, FIB_SOURCE_PLUGIN_LOW,
446 fib_proto_to_dpo (fproto), ip, ip_sw_if_index,
447 ~0, 1, NULL, FIB_ROUTE_PATH_FLAG_NONE);
449 ge->ge_adjs[ii] = adj_nbr_add_or_lock_w_rewrite (fproto,
455 if (gbp_endpoint_is_remote (ge))
457 dpo_id_t policy_dpo = DPO_INVALID;
460 * interpose a policy DPO from the endpoint so that policy
463 gbp_policy_dpo_add_or_lock (fib_proto_to_dpo (fproto),
464 gg->gg_id, ~0, &policy_dpo);
466 fib_table_entry_special_dpo_add
467 (gbp_endpoint_group_get_fib_index (gg, fproto),
469 FIB_SOURCE_PLUGIN_HI, FIB_ENTRY_FLAG_INTERPOSE, &policy_dpo);
473 * send a gratuitous ARP on the EPG's uplink. this is done so
474 * that if this EP has moved from some other place in the
475 * 'fabric', upstream devices are informed
477 if (!(gbp_endpoint_is_remote (ge)) && ~0 != gg->gg_uplink_sw_if_index)
479 gbp_endpoint_add_itf (sw_if_index, gei);
480 if (ip46_address_is_ip4 (ip))
481 send_ip4_garp_w_addr (vlib_get_main (),
482 &ip->ip4, gg->gg_uplink_sw_if_index);
484 send_ip6_na_w_addr (vlib_get_main (),
485 &ip->ip6, gg->gg_uplink_sw_if_index);
494 * count the number of dynamic entries and kick off the scanner
495 * process is this is our first.
497 if (gbp_endpoint_is_remote (ge))
499 gbp_n_learnt_endpoints++;
501 if (1 == gbp_n_learnt_endpoints)
503 vlib_process_signal_event (vlib_get_main (),
504 gbp_scanner_node.index,
505 GBP_ENDPOINT_SCAN_START, 0);
511 * non-remote endpoints (i.e. those not arriving on iVXLAN
512 * tunnels) need to be classifed based on the the input interface.
513 * We enable the GBP-FWD feature only is the group has an uplink
514 * interface (on which the GBP-FWD feature would send UU traffic).
516 l2input_feat_masks_t feats = L2INPUT_FEAT_GBP_SRC_CLASSIFY;
518 if (~0 != gg->gg_uplink_sw_if_index)
519 feats |= L2INPUT_FEAT_GBP_FWD;
520 gbp_itf_set_l2_input_feature (ge->ge_itf, gbp_endpoint_index (ge),
526 *handle = (ge - gbp_endpoint_pool);
528 gbp_endpoint_group_unlock (ggi);
529 GBP_ENDPOINT_INFO ("update: %U", format_gbp_endpoint, gei);
535 gbp_endpoint_delete (index_t gei)
537 gbp_endpoint_group_t *gg;
540 if (pool_is_free_index (gbp_endpoint_pool, gei))
543 GBP_ENDPOINT_INFO ("delete: %U", format_gbp_endpoint, gei);
545 ge = gbp_endpoint_get (gei);
546 gg = gbp_endpoint_group_get (ge->ge_epg);
548 gbp_endpoint_del_mac (&ge->ge_mac, gg->gg_bd_index);
549 l2fib_del_entry (ge->ge_mac.bytes, gg->gg_bd_index, ge->ge_sw_if_index);
550 gbp_itf_set_l2_input_feature (ge->ge_itf, gei, (L2INPUT_FEAT_NONE));
551 gbp_itf_set_l2_output_feature (ge->ge_itf, gei, L2OUTPUT_FEAT_NONE);
553 if (NULL != ge->ge_ips)
555 const ip46_address_t *ip;
558 vec_foreach (ai, ge->ge_adjs)
562 vec_foreach (ip, ge->ge_ips)
564 fib_protocol_t fproto;
567 ip_type = ip46_address_get_type (ip);
568 fproto = fib_proto_from_ip46 (ip_type);
570 gbp_endpoint_del_ip (ip,
571 gbp_endpoint_group_get_fib_index (gg, fproto));
573 bd_add_del_ip_mac (gg->gg_bd_index, ip_type, ip, &ge->ge_mac, 0);
576 * remove a host route via the EPG's BVI
580 .fp_len = ip46_address_get_len (ip),
584 if (gbp_endpoint_is_remote (ge))
586 fib_table_entry_special_remove
587 (gbp_endpoint_group_get_fib_index (gg, fproto),
588 &pfx, FIB_SOURCE_PLUGIN_HI);
591 fib_table_entry_path_remove
592 (gbp_endpoint_group_get_fib_index (gg, fproto),
593 &pfx, FIB_SOURCE_PLUGIN_LOW,
594 fib_proto_to_dpo (fproto), ip,
595 (gbp_endpoint_is_remote (ge) ?
597 gbp_endpoint_group_get_bvi (gg)),
598 ~0, 1, FIB_ROUTE_PATH_FLAG_NONE);
602 if (ge->ge_flags & GBP_ENDPOINT_FLAG_LEARNT)
604 gbp_n_learnt_endpoints--;
606 if (0 == gbp_n_learnt_endpoints)
608 vlib_process_signal_event (vlib_get_main (),
609 gbp_scanner_node.index,
610 GBP_ENDPOINT_SCAN_STOP, 0);
614 gbp_itf_unlock (ge->ge_itf);
615 if (gbp_endpoint_is_remote (ge))
617 vxlan_gbp_tunnel_unlock (ge->ge_sw_if_index);
619 gbp_endpoint_group_unlock (ge->ge_epg);
620 pool_put (gbp_endpoint_pool, ge);
623 typedef struct gbp_endpoint_flush_ctx_t_
627 } gbp_endpoint_flush_ctx_t;
630 gbp_endpoint_flush_cb (index_t gei, void *args)
632 gbp_endpoint_flush_ctx_t *ctx = args;
635 ge = gbp_endpoint_get (gei);
637 if (gbp_endpoint_is_remote (ge) &&
638 ctx->sw_if_index == ge->tun.ge_parent_sw_if_index)
640 vec_add1 (ctx->geis, gei);
643 return (WALK_CONTINUE);
647 * remove all learnt endpoints using the interface
650 gbp_endpoint_flush (u32 sw_if_index)
652 gbp_endpoint_flush_ctx_t ctx = {
653 .sw_if_index = sw_if_index,
657 gbp_endpoint_walk (gbp_endpoint_flush_cb, &ctx);
659 vec_foreach (gei, ctx.geis)
661 gbp_endpoint_delete (*gei);
668 gbp_endpoint_walk (gbp_endpoint_cb_t cb, void *ctx)
673 pool_foreach_index(index, gbp_endpoint_pool,
681 static clib_error_t *
682 gbp_endpoint_cli (vlib_main_t * vm,
683 unformat_input_t * input, vlib_cli_command_t * cmd)
685 ip46_address_t ip = ip46_address_initializer, *ips = NULL;
686 mac_address_t mac = ZERO_MAC_ADDRESS;
687 vnet_main_t *vnm = vnet_get_main ();
688 u32 epg_id = EPG_INVALID;
689 u32 handle = INDEX_INVALID;
690 u32 sw_if_index = ~0;
694 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
696 ip46_address_reset (&ip);
698 if (unformat (input, "%U", unformat_vnet_sw_interface,
701 else if (unformat (input, "add"))
703 else if (unformat (input, "del"))
705 else if (unformat (input, "epg %d", &epg_id))
707 else if (unformat (input, "handle %d", &handle))
709 else if (unformat (input, "ip %U", unformat_ip4_address, &ip.ip4))
711 else if (unformat (input, "ip %U", unformat_ip6_address, &ip.ip6))
713 else if (unformat (input, "mac %U", unformat_mac_address, &mac))
721 if (~0 == sw_if_index)
722 return clib_error_return (0, "interface must be specified");
723 if (EPG_INVALID == epg_id)
724 return clib_error_return (0, "EPG-ID must be specified");
727 gbp_endpoint_update (sw_if_index, ips, &mac, epg_id,
728 GBP_ENDPOINT_FLAG_NONE, NULL, NULL, &handle);
731 return clib_error_return (0, "GBP Endpoint update returned %d", rv);
733 vlib_cli_output (vm, "handle %d\n", handle);
737 if (INDEX_INVALID == handle)
738 return clib_error_return (0, "handle must be specified");
740 gbp_endpoint_delete (handle);
750 * Configure a GBP Endpoint
753 * @cliexstart{set gbp endpoint [del] <interface> epg <ID> ip <IP>}
757 VLIB_CLI_COMMAND (gbp_endpoint_cli_node, static) = {
758 .path = "gbp endpoint",
759 .short_help = "gbp endpoint [del] <interface> epg <ID> ip <IP> mac <MAC>",
760 .function = gbp_endpoint_cli,
765 format_gbp_endpoint (u8 * s, va_list * args)
767 index_t gei = va_arg (*args, index_t);
768 const ip46_address_t *ip;
771 ge = gbp_endpoint_get (gei);
773 s = format (s, "[@%d] ", gei);
774 s = format (s, "IPs:[");
776 vec_foreach (ip, ge->ge_ips)
778 s = format (s, "%U, ", format_ip46_address, ip, IP46_TYPE_ANY);
782 s = format (s, " MAC:%U", format_mac_address_t, &ge->ge_mac);
783 s = format (s, " EPG-ID:%d", ge->ge_epg_id);
784 if (GBP_ENDPOINT_FLAG_NONE != ge->ge_flags)
786 s = format (s, " flags:%U", format_gbp_endpoint_flags, ge->ge_flags);
789 s = format (s, " itf:[%U]", format_gbp_itf, ge->ge_itf);
790 s = format (s, " last-time:[%f]", ge->ge_last_time);
796 gbp_endpoint_show_one (index_t gei, void *ctx)
801 vlib_cli_output (vm, " %U", format_gbp_endpoint, gei);
803 return (WALK_CONTINUE);
807 gbp_endpoint_walk_ip_itf (const clib_bihash_kv_24_8_t * kvp, void *arg)
815 gbp_endpoint_extract_key_ip_itf (kvp, &ip, &sw_if_index);
817 vlib_cli_output (vm, " {%U, %U} -> %d",
818 format_ip46_address, &ip, IP46_TYPE_ANY,
819 format_vnet_sw_if_index_name, vnet_get_main (),
820 sw_if_index, kvp->value);
824 gbp_endpoint_walk_mac_itf (const clib_bihash_kv_16_8_t * kvp, void *arg)
832 gbp_endpoint_extract_key_mac_itf (kvp, &mac, &sw_if_index);
834 vlib_cli_output (vm, " {%U, %U} -> %d",
835 format_mac_address_t, &mac,
836 format_vnet_sw_if_index_name, vnet_get_main (),
837 sw_if_index, kvp->value);
840 static clib_error_t *
841 gbp_endpoint_show (vlib_main_t * vm,
842 unformat_input_t * input, vlib_cli_command_t * cmd)
844 u32 show_dbs, handle;
846 handle = INDEX_INVALID;
849 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
851 if (unformat (input, "%d", &handle))
853 else if (unformat (input, "db"))
859 if (INDEX_INVALID != handle)
861 vlib_cli_output (vm, "%U", format_gbp_endpoint, handle);
865 vlib_cli_output (vm, "\nDatabases:");
866 clib_bihash_foreach_key_value_pair_24_8 (&gbp_ep_db.ged_by_ip_rd,
867 gbp_endpoint_walk_ip_itf, vm);
868 clib_bihash_foreach_key_value_pair_16_8
869 (&gbp_ep_db.ged_by_mac_bd, gbp_endpoint_walk_mac_itf, vm);
873 vlib_cli_output (vm, "Endpoints:");
874 gbp_endpoint_walk (gbp_endpoint_show_one, vm);
881 * Show Group Based Policy Endpoints and derived information
884 * @cliexstart{show gbp endpoint}
888 VLIB_CLI_COMMAND (gbp_endpoint_show_node, static) = {
889 .path = "show gbp endpoint",
890 .short_help = "show gbp endpoint\n",
891 .function = gbp_endpoint_show,
896 gbp_endpoint_check (index_t gei, f64 start_time)
900 ge = gbp_endpoint_get (gei);
902 GBP_ENDPOINT_DBG ("scan at:%f -> %U", start_time, format_gbp_endpoint, gei);
904 if ((ge->ge_flags & GBP_ENDPOINT_FLAG_LEARNT) &&
905 ((start_time - ge->ge_last_time) > GBP_ENDPOINT_INACTIVE_TIME))
907 gbp_endpoint_delete (gei);
912 gbp_endpoint_scan_l2 (vlib_main_t * vm)
914 clib_bihash_16_8_t *gte_table = &gbp_ep_db.ged_by_mac_bd;
915 f64 last_start, start_time, delta_t;
919 last_start = start_time = vlib_time_now (vm);
921 for (i = 0; i < gte_table->nbuckets; i++)
923 clib_bihash_bucket_16_8_t *b;
924 clib_bihash_value_16_8_t *v;
926 /* allow no more than 20us without a pause */
927 delta_t = vlib_time_now (vm) - last_start;
930 /* suspend for 100 us */
931 vlib_process_suspend (vm, 100e-6);
932 last_start = vlib_time_now (vm);
935 b = >e_table->buckets[i];
938 v = clib_bihash_get_value_16_8 (gte_table, b->offset);
940 for (j = 0; j < (1 << b->log2_pages); j++)
942 for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
944 if (clib_bihash_is_free_16_8 (&v->kvp[k]))
947 gbp_endpoint_check (v->kvp[k].value, start_time);
950 * Note: we may have just freed the bucket's backing
951 * storage, so check right here...
964 gbp_endpoint_scan_l3 (vlib_main_t * vm)
966 clib_bihash_24_8_t *gte_table = &gbp_ep_db.ged_by_ip_rd;
967 f64 last_start, start_time, delta_t;
971 last_start = start_time = vlib_time_now (vm);
973 for (i = 0; i < gte_table->nbuckets; i++)
975 clib_bihash_bucket_24_8_t *b;
976 clib_bihash_value_24_8_t *v;
978 /* allow no more than 20us without a pause */
979 delta_t = vlib_time_now (vm) - last_start;
982 /* suspend for 100 us */
983 vlib_process_suspend (vm, 100e-6);
984 last_start = vlib_time_now (vm);
987 b = >e_table->buckets[i];
990 v = clib_bihash_get_value_24_8 (gte_table, b->offset);
992 for (j = 0; j < (1 << b->log2_pages); j++)
994 for (k = 0; k < BIHASH_KVP_PER_PAGE; k++)
996 if (clib_bihash_is_free_24_8 (&v->kvp[k]))
999 gbp_endpoint_check (v->kvp[k].value, start_time);
1002 * Note: we may have just freed the bucket's backing
1003 * storage, so check right here...
1016 gbp_endpoint_scan (vlib_main_t * vm)
1018 gbp_endpoint_scan_l2 (vm);
1019 gbp_endpoint_scan_l3 (vm);
1023 gbp_learn_set_inactive_threshold (u32 threshold)
1025 GBP_ENDPOINT_INACTIVE_TIME = threshold;
1029 gbp_endpoint_scan_threshold (void)
1031 return (GBP_ENDPOINT_INACTIVE_TIME);
1034 #define GBP_EP_HASH_NUM_BUCKETS (2 * 1024)
1035 #define GBP_EP_HASH_MEMORY_SIZE (1 << 20)
1037 static clib_error_t *
1038 gbp_endpoint_init (vlib_main_t * vm)
1040 clib_bihash_init_24_8 (&gbp_ep_db.ged_by_ip_rd,
1041 "GBP Endpoints - IP/RD",
1042 GBP_EP_HASH_NUM_BUCKETS, GBP_EP_HASH_MEMORY_SIZE);
1044 clib_bihash_init_16_8 (&gbp_ep_db.ged_by_mac_bd,
1045 "GBP Endpoints - MAC/BD",
1046 GBP_EP_HASH_NUM_BUCKETS, GBP_EP_HASH_MEMORY_SIZE);
1048 gbp_ep_logger = vlib_log_register_class ("gbp", "ep");
1053 VLIB_INIT_FUNCTION (gbp_endpoint_init);
1056 * fd.io coding-style-patch-verification: ON
1059 * eval: (c-set-style "gnu")