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>
21 #include <vnet/ethernet/arp_packet.h>
22 #include <vnet/l2/l2_input.h>
23 #include <vnet/l2/l2_output.h>
24 #include <vnet/l2/feat_bitmap.h>
26 gbp_ep_by_itf_db_t gbp_ep_by_itf_db;
27 gbp_ep_by_mac_itf_db_t gbp_ep_by_mac_itf_db;
28 gbp_ep_by_ip_itf_db_t gbp_ep_by_ip_itf_db;
31 * Pool of GBP endpoints
33 gbp_endpoint_t *gbp_endpoint_pool;
36 /* gbp_itf_epg_update (u32 sw_if_index, epg_id_t src_epg, u8 do_policy) */
38 /* vec_validate_init_empty (gbp_itf_to_epg_db.gte_vec, */
39 /* sw_if_index, ITF_INVALID); */
41 /* if (0 == gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count) */
43 /* l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY, */
45 /* l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 1); */
47 /* l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY, */
50 /* gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg = src_epg; */
51 /* gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count++; */
55 /* gbp_itf_epg_delete (u32 sw_if_index) */
57 /* if (vec_len (gbp_itf_to_epg_db.gte_vec) <= sw_if_index) */
60 /* if (1 == gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count) */
62 /* gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_epg = EPG_INVALID; */
64 /* l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY, */
66 /* l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 0); */
67 /* l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY, 0); */
69 /* gbp_itf_to_epg_db.gte_vec[sw_if_index].gi_ref_count--; */
73 gbp_endpoint_mk_key_mac_itf (const mac_address_t * mac,
74 u32 sw_if_index, clib_bihash_kv_16_8_t * key)
76 key->key[0] = mac_address_as_u64 (mac);
77 key->key[1] = sw_if_index;
81 gbp_endpoint_extract_key_mac_itf (const clib_bihash_kv_16_8_t * key,
82 mac_address_t * mac, u32 * sw_if_index)
84 mac_address_from_u64 (key->key[0], mac);
85 *sw_if_index = key->key[1];
89 gbp_endpoint_find_mac_itf (const mac_address_t * mac, u32 sw_if_index)
91 clib_bihash_kv_16_8_t key, value;
94 gbp_endpoint_mk_key_mac_itf (mac, sw_if_index, &key);
97 clib_bihash_search_16_8 (&gbp_ep_by_mac_itf_db.gte_table, &key, &value);
102 return (gbp_endpoint_get (value.value));
106 gbp_endpoint_mk_key_ip_itf (const ip46_address_t * ip,
107 u32 sw_if_index, clib_bihash_kv_24_8_t * key)
109 key->key[0] = ip->as_u64[0];
110 key->key[1] = ip->as_u64[1];
111 key->key[2] = sw_if_index;
115 gbp_endpoint_extract_key_ip_itf (const clib_bihash_kv_24_8_t * key,
116 ip46_address_t * ip, u32 * sw_if_index)
118 ip->as_u64[0] = key->key[0];
119 ip->as_u64[1] = key->key[1];
120 *sw_if_index = key->key[2];
124 gbp_endpoint_find_ip_itf (const ip46_address_t * ip, u32 sw_if_index)
126 clib_bihash_kv_24_8_t key, value;
129 gbp_endpoint_mk_key_ip_itf (ip, sw_if_index, &key);
131 rv = clib_bihash_search_24_8 (&gbp_ep_by_ip_itf_db.gte_table, &key, &value);
136 return (gbp_endpoint_get (value.value));
140 gbp_endpoint_find_itf (u32 sw_if_index)
142 /* if (vec_len(gbp_ep_by_itf_db.gte_vec) >= sw_if_index) */
145 /* vec_search(gbp_ep_by_itf_db.gte_vec[sw_if_index], */
146 /* return (gbp_endpoint_get(gbp_ep_by_itf_db.gte_vec[sw_if_index][0])); */
151 gbp_endpoint_add_mac_itf (const mac_address_t * mac,
152 u32 sw_if_index, index_t gbpei)
154 clib_bihash_kv_16_8_t key;
157 gbp_endpoint_mk_key_mac_itf (mac, sw_if_index, &key);
160 rv = clib_bihash_add_del_16_8 (&gbp_ep_by_mac_itf_db.gte_table, &key, 1);
166 gbp_endpoint_add_ip_itf (const ip46_address_t * ip,
167 u32 sw_if_index, index_t gbpei)
169 clib_bihash_kv_24_8_t key;
172 gbp_endpoint_mk_key_ip_itf (ip, sw_if_index, &key);
175 rv = clib_bihash_add_del_24_8 (&gbp_ep_by_ip_itf_db.gte_table, &key, 1);
181 gbp_endpoint_add_itf (u32 sw_if_index, index_t gbpei)
183 vec_validate_init_empty (gbp_ep_by_itf_db.gte_vec, sw_if_index,
186 if (INDEX_INVALID == gbp_ep_by_itf_db.gte_vec[sw_if_index])
188 l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY,
190 l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 1);
191 l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY, 1);
193 gbp_ep_by_itf_db.gte_vec[sw_if_index] = gbpei;
197 gbp_endpoint_del_mac_itf (const mac_address_t * mac, u32 sw_if_index)
199 clib_bihash_kv_16_8_t key;
201 gbp_endpoint_mk_key_mac_itf (mac, sw_if_index, &key);
203 clib_bihash_add_del_16_8 (&gbp_ep_by_mac_itf_db.gte_table, &key, 0);
207 gbp_endpoint_del_ip_itf (const ip46_address_t * ip, u32 sw_if_index)
209 clib_bihash_kv_24_8_t key;
211 gbp_endpoint_mk_key_ip_itf (ip, sw_if_index, &key);
213 clib_bihash_add_del_24_8 (&gbp_ep_by_ip_itf_db.gte_table, &key, 0);
217 gbp_endpoint_del_itf (u32 sw_if_index)
219 if (vec_len (gbp_ep_by_itf_db.gte_vec) <= sw_if_index)
222 l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_SRC_CLASSIFY, 0);
223 l2input_intf_bitmap_enable (sw_if_index, L2INPUT_FEAT_GBP_FWD, 0);
224 l2output_intf_bitmap_enable (sw_if_index, L2OUTPUT_FEAT_GBP_POLICY, 0);
226 gbp_ep_by_itf_db.gte_vec[sw_if_index] = INDEX_INVALID;
230 gbp_endpoint_index (const gbp_endpoint_t * gbpe)
232 return (gbpe - gbp_endpoint_pool);
236 gbp_endpoint_update (u32 sw_if_index,
237 const ip46_address_t * ips,
238 const mac_address_t * mac, epg_id_t epg_id, u32 * handle)
240 gbp_endpoint_group_t *gepg;
241 const ip46_address_t *ip;
242 gbp_endpoint_t *gbpe;
245 gepg = gbp_endpoint_group_find (epg_id);
248 return (VNET_API_ERROR_NO_SUCH_ENTRY);
251 * find an existing endpoint matching one of the key types
255 gbpe = gbp_endpoint_find_mac_itf (mac, sw_if_index);
257 if (NULL == gbpe && NULL != ips)
259 vec_foreach (ip, ips)
261 gbpe = gbp_endpoint_find_ip_itf (ip, sw_if_index);
269 gbpe = gbp_endpoint_find_itf (sw_if_index);
279 pool_get (gbp_endpoint_pool, gbpe);
280 gbpei = gbp_endpoint_index (gbpe);
282 gbpe->ge_epg_id = epg_id;
283 gbpe->ge_sw_if_index = sw_if_index;
284 gbp_endpoint_add_itf (gbpe->ge_sw_if_index, gbpei);
291 gbp_endpoint_add_mac_itf (mac, sw_if_index, gbpei);
296 vec_validate (gbpe->ge_ips, vec_len (ips) - 1);
297 vec_foreach_index (ii, ips)
299 ip46_address_copy (&gbpe->ge_ips[ii], &ips[ii]);
302 gbp_endpoint_add_ip_itf (&ips[ii], sw_if_index, gbpei);
305 * send a gratuitous ARP on the EPG's uplink. this is done so
306 * that if this EP has moved from some other place in the
307 * 'fabric', upstream devices are informed
309 if (ip46_address_is_ip4 (&ips[ii]))
310 send_ip4_garp_w_addr (vlib_get_main (),
312 gepg->gepg_uplink_sw_if_index);
314 send_ip6_na_w_addr (vlib_get_main (),
316 gepg->gepg_uplink_sw_if_index);
323 * update existing entry..
328 *handle = (gbpe - gbp_endpoint_pool);
334 gbp_endpoint_delete (u32 handle)
336 gbp_endpoint_t *gbpe;
338 if (pool_is_free_index (gbp_endpoint_pool, handle))
341 gbpe = pool_elt_at_index (gbp_endpoint_pool, handle);
343 gbp_endpoint_del_itf (gbpe->ge_sw_if_index);
345 if (!mac_address_is_zero (&gbpe->ge_mac))
347 gbp_endpoint_del_mac_itf (&gbpe->ge_mac, gbpe->ge_sw_if_index);
350 if (NULL != gbpe->ge_ips)
352 const ip46_address_t *ip;
354 vec_foreach (ip, gbpe->ge_ips)
356 gbp_endpoint_del_ip_itf (ip, gbpe->ge_sw_if_index);
359 pool_put (gbp_endpoint_pool, gbpe);
363 gbp_endpoint_walk (gbp_endpoint_cb_t cb, void *ctx)
365 gbp_endpoint_t *gbpe;
368 pool_foreach(gbpe, gbp_endpoint_pool,
376 static clib_error_t *
377 gbp_endpoint_cli (vlib_main_t * vm,
378 unformat_input_t * input, vlib_cli_command_t * cmd)
380 ip46_address_t ip = ip46_address_initializer, *ips = NULL;
381 mac_address_t mac = ZERO_MAC_ADDRESS;
382 vnet_main_t *vnm = vnet_get_main ();
383 epg_id_t epg_id = EPG_INVALID;
384 u32 handle = INDEX_INVALID;
385 u32 sw_if_index = ~0;
389 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
391 ip46_address_reset (&ip);
393 if (unformat (input, "%U", unformat_vnet_sw_interface,
396 else if (unformat (input, "add"))
398 else if (unformat (input, "del"))
400 else if (unformat (input, "epg %d", &epg_id))
402 else if (unformat (input, "handle %d", &handle))
404 else if (unformat (input, "ip %U", unformat_ip4_address, &ip.ip4))
406 else if (unformat (input, "ip %U", unformat_ip6_address, &ip.ip6))
408 else if (unformat (input, "mac %U", unformat_mac_address, &mac))
416 if (~0 == sw_if_index)
417 return clib_error_return (0, "interface must be specified");
418 if (EPG_INVALID == epg_id)
419 return clib_error_return (0, "EPG-ID must be specified");
421 rv = gbp_endpoint_update (sw_if_index, ips, &mac, epg_id, &handle);
424 return clib_error_return (0, "GBP Endpoint update returned %d", rv);
426 vlib_cli_output (vm, "handle %d\n", handle);
430 if (INDEX_INVALID == handle)
431 return clib_error_return (0, "handle must be specified");
433 gbp_endpoint_delete (handle);
443 * Configure a GBP Endpoint
446 * @cliexstart{set gbp endpoint [del] <interface> epg <ID> ip <IP>}
450 VLIB_CLI_COMMAND (gbp_endpoint_cli_node, static) = {
451 .path = "gbp endpoint",
452 .short_help = "gbp endpoint [del] <interface> epg <ID> ip <IP> mac <MAC>",
453 .function = gbp_endpoint_cli,
458 format_gbp_endpoint (u8 * s, va_list * args)
460 index_t gbpei = va_arg (*args, index_t);
461 vnet_main_t *vnm = vnet_get_main ();
462 const ip46_address_t *ip;
463 gbp_endpoint_t *gbpe;
465 gbpe = gbp_endpoint_get (gbpei);
467 s = format (s, "[@%d] ", gbpei);
469 format (s, "%U", format_vnet_sw_if_index_name, vnm, gbpe->ge_sw_if_index);
470 s = format (s, ", IPs:[");
472 vec_foreach (ip, gbpe->ge_ips)
474 s = format (s, "%U, ", format_ip46_address, ip, IP46_TYPE_ANY);
478 s = format (s, " MAC:%U", format_mac_address_t, &gbpe->ge_mac);
479 s = format (s, " EPG-ID:%d", gbpe->ge_epg_id);
485 gbp_endpoint_show_one (gbp_endpoint_t * gbpe, void *ctx)
490 vlib_cli_output (vm, " %U", format_gbp_endpoint, gbp_endpoint_index (gbpe));
492 return (WALK_CONTINUE);
496 gbp_endpoint_walk_ip_itf (const clib_bihash_kv_24_8_t * kvp, void *arg)
504 gbp_endpoint_extract_key_ip_itf (kvp, &ip, &sw_if_index);
506 vlib_cli_output (vm, " {%U, %U} -> %d",
507 format_ip46_address, &ip, IP46_TYPE_ANY,
508 format_vnet_sw_if_index_name, vnet_get_main (),
509 sw_if_index, kvp->value);
513 gbp_endpoint_walk_mac_itf (const clib_bihash_kv_16_8_t * kvp, void *arg)
521 gbp_endpoint_extract_key_mac_itf (kvp, &mac, &sw_if_index);
523 vlib_cli_output (vm, " {%U, %U} -> %d",
524 format_mac_address_t, &mac,
525 format_vnet_sw_if_index_name, vnet_get_main (),
526 sw_if_index, kvp->value);
529 static clib_error_t *
530 gbp_endpoint_show (vlib_main_t * vm,
531 unformat_input_t * input, vlib_cli_command_t * cmd)
533 u32 sw_if_index, show_dbs, handle;
535 handle = INDEX_INVALID;
538 while (unformat_check_input (input) != UNFORMAT_END_OF_INPUT)
540 if (unformat (input, "%d", &handle))
542 else if (unformat (input, "db", &handle))
548 if (INDEX_INVALID != handle)
550 vlib_cli_output (vm, "%U", format_gbp_endpoint, handle);
554 vlib_cli_output (vm, "\nDatabases:");
555 clib_bihash_foreach_key_value_pair_24_8 (&gbp_ep_by_ip_itf_db.gte_table,
556 gbp_endpoint_walk_ip_itf, vm);
557 clib_bihash_foreach_key_value_pair_16_8
558 (&gbp_ep_by_mac_itf_db.gte_table, gbp_endpoint_walk_mac_itf, vm);
560 vec_foreach_index (sw_if_index, gbp_ep_by_itf_db.gte_vec)
562 if (INDEX_INVALID != gbp_ep_by_itf_db.gte_vec[sw_if_index])
563 vlib_cli_output (vm, " {%U} -> %d",
564 format_vnet_sw_if_index_name, vnet_get_main (),
566 gbp_ep_by_itf_db.gte_vec[sw_if_index]);
571 vlib_cli_output (vm, "Endpoints:");
572 gbp_endpoint_walk (gbp_endpoint_show_one, vm);
579 * Show Group Based Policy Endpoints and derived information
582 * @cliexstart{show gbp endpoint}
586 VLIB_CLI_COMMAND (gbp_endpoint_show_node, static) = {
587 .path = "show gbp endpoint",
588 .short_help = "show gbp endpoint\n",
589 .function = gbp_endpoint_show,
593 #define GBP_EP_HASH_NUM_BUCKETS (2 * 1024)
594 #define GBP_EP_HASH_MEMORY_SIZE (1 << 20)
596 static clib_error_t *
597 gbp_endpoint_init (vlib_main_t * vm)
599 clib_bihash_init_24_8 (&gbp_ep_by_ip_itf_db.gte_table,
600 "GBP Endpoints - IP/Interface",
601 GBP_EP_HASH_NUM_BUCKETS, GBP_EP_HASH_MEMORY_SIZE);
603 clib_bihash_init_16_8 (&gbp_ep_by_mac_itf_db.gte_table,
604 "GBP Endpoints - MAC/Interface",
605 GBP_EP_HASH_NUM_BUCKETS, GBP_EP_HASH_MEMORY_SIZE);
610 VLIB_INIT_FUNCTION (gbp_endpoint_init);
613 * fd.io coding-style-patch-verification: ON
616 * eval: (c-set-style "gnu")