Recheck-request: github-robot
On Thu, Nov 14, 2024 at 11:47:22AM +0100, Max Lamprecht via dev wrote:
> This patch moves the nat_addresses calculation to an own engine node.
>
> Previously the nat_address calculation was executed at every pinctrl_run
> (send_garp_rarp_prepare). This can cause high cpu usage and delayed
> actions on gateway-chassis(500 LRPs+).
>
> perf trace:
> - 98.83% main
> - 79.69% pinctrl_run
> - 77.71% send_garp_rarp_prepare
> - 55.49% get_nat_addresses_and_keys
> - 36.76% consider_nat_address
> - 18.13% lport_lookup_by_name
> - 13.58% sset_destroy
>
> Co-authored-by: Ihtisham ul Haq <[email protected]>
> Signed-off-by: Ihtisham ul Haq <[email protected]>
> Signed-off-by: Max Lamprecht <[email protected]>
> ---
> controller/ovn-controller.c | 341 +++++++++++++++++++++++++++++++-
> controller/pinctrl.c | 381 ++++++------------------------------
> controller/pinctrl.h | 14 +-
> 3 files changed, 410 insertions(+), 326 deletions(-)
>
> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> index 98b144699..49bc6d86c 100644
> --- a/controller/ovn-controller.c
> +++ b/controller/ovn-controller.c
> @@ -3359,6 +3359,319 @@ en_dns_cache_cleanup(void *data OVS_UNUSED)
> ovn_dns_cache_destroy();
> }
>
> +static void *
> +en_nat_addresses_init(struct engine_node *node OVS_UNUSED,
> + struct engine_arg *arg OVS_UNUSED)
> +{
> + struct ed_type_nat_addresses *data = xzalloc(sizeof *data);
> + shash_init(&data->nat_addresses);
> + sset_init(&data->localnet_vifs);
> + sset_init(&data->local_l3gw_ports);
> + sset_init(&data->nat_ip_keys);
> + return data;
> +}
> +
> +/* Extracts the mac, IPv4 and IPv6 addresses, and logical port from
> + * 'addresses' which should be of the format 'MAC [IP1 IP2 ..]
> + * [is_chassis_resident("LPORT_NAME")]', where IPn should be a valid IPv4
> + * or IPv6 address, and stores them in the 'ipv4_addrs' and 'ipv6_addrs'
> + * fields of 'laddrs'. The logical port name is stored in 'lport'.
> + *
> + * Returns true if at least 'MAC' is found in 'address', false otherwise.
> + *
> + * The caller must call destroy_lport_addresses() and free(*lport). */
> +static bool
> +extract_addresses_with_port(const char *addresses,
> + struct lport_addresses *laddrs,
> + char **lport)
> +{
> + int ofs;
> + if (!extract_addresses(addresses, laddrs, &ofs)) {
> + return false;
> + } else if (!addresses[ofs]) {
> + return true;
> + }
> +
> + struct lexer lexer;
> + lexer_init(&lexer, addresses + ofs);
> + lexer_get(&lexer);
> +
> + if (lexer.error || lexer.token.type != LEX_T_ID
> + || !lexer_match_id(&lexer, "is_chassis_resident")) {
> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> + VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", addresses);
> + lexer_destroy(&lexer);
> + return true;
> + }
> +
> + if (!lexer_match(&lexer, LEX_T_LPAREN)) {
> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> + VLOG_INFO_RL(&rl, "Syntax error: expecting '(' after "
> + "'is_chassis_resident' in address '%s'",
> addresses);
> + lexer_destroy(&lexer);
> + return false;
> + }
> +
> + if (lexer.token.type != LEX_T_STRING) {
> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> + VLOG_INFO_RL(&rl,
> + "Syntax error: expecting quoted string after "
> + "'is_chassis_resident' in address '%s'", addresses);
> + lexer_destroy(&lexer);
> + return false;
> + }
> +
> + *lport = xstrdup(lexer.token.s);
> +
> + lexer_get(&lexer);
> + if (!lexer_match(&lexer, LEX_T_RPAREN)) {
> + static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> + VLOG_INFO_RL(&rl, "Syntax error: expecting ')' after quoted string
> in "
> + "'is_chassis_resident()' in address '%s'",
> + addresses);
> + lexer_destroy(&lexer);
> + return false;
> + }
> +
> + lexer_destroy(&lexer);
> + return true;
> +}
> +
> +static void
> +consider_nat_address(struct ovsdb_idl_index *sbrec_port_binding_by_name,
> + const char *nat_address,
> + const struct sbrec_port_binding *pb,
> + struct sset *nat_address_keys,
> + const struct sbrec_chassis *chassis,
> + const struct sset *active_tunnels,
> + struct shash *nat_addresses)
> +{
> + struct lport_addresses *laddrs = xmalloc(sizeof *laddrs);
> + char *lport = NULL;
> + if (!extract_addresses_with_port(nat_address, laddrs, &lport)
> + || (!lport && !strcmp(pb->type, "patch"))
> + || (lport && !lport_is_chassis_resident(
> + sbrec_port_binding_by_name, chassis,
> + active_tunnels, lport))) {
> + destroy_lport_addresses(laddrs);
> + free(laddrs);
> + free(lport);
> + return;
> + }
> + free(lport);
> +
> + int i;
> + for (i = 0; i < laddrs->n_ipv4_addrs; i++) {
> + char *name = xasprintf("%s-%s", pb->logical_port,
> + laddrs->ipv4_addrs[i].addr_s);
> + sset_add(nat_address_keys, name);
> + free(name);
> + }
> + if (laddrs->n_ipv4_addrs == 0) {
> + char *name = xasprintf("%s-noip", pb->logical_port);
> + sset_add(nat_address_keys, name);
> + free(name);
> + }
> + shash_add(nat_addresses, pb->logical_port, laddrs);
> +}
> +
> +static void
> +get_nat_addresses_and_keys(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
> + struct sset *nat_address_keys,
> + struct sset *local_l3gw_ports,
> + const struct sbrec_chassis *chassis,
> + const struct sset *active_tunnels,
> + struct shash *nat_addresses)
> +{
> + const char *gw_port;
> + SSET_FOR_EACH (gw_port, local_l3gw_ports) {
> + const struct sbrec_port_binding *pb;
> +
> + pb = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
> + if (!pb) {
> + continue;
> + }
> +
> + if (pb->n_nat_addresses) {
> + for (int i = 0; i < pb->n_nat_addresses; i++) {
> + consider_nat_address(sbrec_port_binding_by_name,
> + pb->nat_addresses[i], pb,
> + nat_address_keys, chassis,
> + active_tunnels,
> + nat_addresses);
> + }
> + } else {
> + /* Continue to support options:nat-addresses for version
> + * upgrade. */
> + const char *nat_addresses_options = smap_get(&pb->options,
> + "nat-addresses");
> + if (nat_addresses_options) {
> + consider_nat_address(sbrec_port_binding_by_name,
> + nat_addresses_options, pb,
> + nat_address_keys, chassis,
> + active_tunnels,
> + nat_addresses);
> + }
> + }
> + }
> +}
> +
> +/* Get localnet vifs, local l3gw ports and ofport for localnet patch ports.
> */
> +static void
> +get_localnet_vifs_l3gwports(
> + struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
> + struct ovsdb_idl_index *sbrec_port_binding_by_name,
> + const struct ovsrec_bridge *br_int,
> + const struct sbrec_chassis *chassis,
> + const struct hmap *local_datapaths,
> + struct sset *localnet_vifs,
> + struct sset *local_l3gw_ports)
> +{
> + for (int i = 0; i < br_int->n_ports; i++) {
> + const struct ovsrec_port *port_rec = br_int->ports[i];
> + if (!strcmp(port_rec->name, br_int->name)) {
> + continue;
> + }
> + const char *tunnel_id = smap_get(&port_rec->external_ids,
> + "ovn-chassis-id");
> + if (tunnel_id &&
> + encaps_tunnel_id_match(tunnel_id, chassis->name, NULL,
> NULL)) {
> + continue;
> + }
> + const char *localnet = smap_get(&port_rec->external_ids,
> + "ovn-localnet-port");
> + if (localnet) {
> + continue;
> + }
> + for (int j = 0; j < port_rec->n_interfaces; j++) {
> + const struct ovsrec_interface *iface_rec =
> port_rec->interfaces[j];
> + if (!iface_rec->n_ofport) {
> + continue;
> + }
> + /* Get localnet vif. */
> + const char *iface_id = smap_get(&iface_rec->external_ids,
> + "iface-id");
> + if (!iface_id) {
> + continue;
> + }
> + const struct sbrec_port_binding *pb
> + = lport_lookup_by_name(sbrec_port_binding_by_name, iface_id);
> + if (!pb || pb->chassis != chassis) {
> + continue;
> + }
> + if (!iface_rec->link_state ||
> + strcmp(iface_rec->link_state, "up")) {
> + continue;
> + }
> + struct local_datapath *ld
> + = get_local_datapath(local_datapaths,
> + pb->datapath->tunnel_key);
> + if (ld && ld->localnet_port) {
> + sset_add(localnet_vifs, iface_id);
> + }
> + }
> + }
> +
> + struct sbrec_port_binding *target = sbrec_port_binding_index_init_row(
> + sbrec_port_binding_by_datapath);
> +
> + const struct local_datapath *ld;
> + HMAP_FOR_EACH (ld, hmap_node, local_datapaths) {
> + const struct sbrec_port_binding *pb;
> +
> + if (!ld->localnet_port) {
> + continue;
> + }
> +
> + /* Get l3gw ports. Consider port bindings with type "l3gateway"
> + * that connect to gateway routers (if local), and consider port
> + * bindings of type "patch" since they might connect to
> + * distributed gateway ports with NAT addresses. */
> +
> + sbrec_port_binding_index_set_datapath(target, ld->datapath);
> + SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, target,
> + sbrec_port_binding_by_datapath) {
> + if ((!strcmp(pb->type, "l3gateway") && pb->chassis == chassis)
> + || !strcmp(pb->type, "patch")) {
> + sset_add(local_l3gw_ports, pb->logical_port);
> + }
> + }
> + }
> + sbrec_port_binding_index_destroy_row(target);
> +}
> +
> +static void
> +en_nat_addresses_run(struct engine_node *node, void *data OVS_UNUSED)
> +{
> + struct ed_type_nat_addresses *nat_addresses = data;
> + const struct ovsrec_open_vswitch_table *ovs_table =
> + EN_OVSDB_GET(engine_get_input("OVS_open_vswitch", node));
> + const char *chassis_id = get_ovs_chassis_id(ovs_table);
> + struct ovsdb_idl_index *sbrec_chassis_by_name =
> + engine_ovsdb_node_get_index(
> + engine_get_input("SB_chassis", node),
> + "name");
> + const struct sbrec_chassis *chassis
> + = chassis_lookup_by_name(sbrec_chassis_by_name, chassis_id);
> +
> + struct ovsdb_idl_index *sbrec_pb_by_datapath =
> + engine_ovsdb_node_get_index(
> + engine_get_input("SB_port_binding", node),
> + "datapath");
> + struct ovsdb_idl_index *sbrec_pb_by_name =
> + engine_ovsdb_node_get_index(
> + engine_get_input("SB_port_binding", node),
> + "name");
> + const struct ovsrec_bridge_table *bridge_table =
> + EN_OVSDB_GET(engine_get_input("OVS_bridge", node));
> + const struct ovsrec_bridge *br_int = get_br_int(bridge_table, ovs_table);
> +
> + struct ed_type_runtime_data *rt_data =
> + engine_get_input_data("runtime_data", node);
> + const struct hmap *local_datapaths = &rt_data->local_datapaths;
> + const struct sset *active_tunnels = &rt_data->active_tunnels;
> +
> + struct shash_node *nat_node;
> + SHASH_FOR_EACH (nat_node, &nat_addresses->nat_addresses) {
> + struct lport_addresses *laddrs = nat_node->data;
> + destroy_lport_addresses(laddrs);
> + free(laddrs);
> + }
> + shash_clear(&nat_addresses->nat_addresses);
> + sset_clear(&nat_addresses->localnet_vifs);
> + sset_clear(&nat_addresses->local_l3gw_ports);
> + sset_clear(&nat_addresses->nat_ip_keys);
> +
> + get_localnet_vifs_l3gwports(sbrec_pb_by_datapath,
> + sbrec_pb_by_name,
> + br_int, chassis, local_datapaths,
> + &nat_addresses->localnet_vifs,
> + &nat_addresses->local_l3gw_ports);
> +
> + get_nat_addresses_and_keys(sbrec_pb_by_name,
> + &nat_addresses->nat_ip_keys,
> + &nat_addresses->local_l3gw_ports,
> + chassis, active_tunnels,
> + &nat_addresses->nat_addresses);
> +
> + engine_set_node_state(node, EN_UPDATED);
> +}
> +
> +static bool
> +nat_addresses_change_handler(struct engine_node *node, void *data)
> +{
> + en_nat_addresses_run(node, data);
> + return true;
> +}
> +
> +static void
> +en_nat_addresses_cleanup(void *data OVS_UNUSED){
> + struct ed_type_nat_addresses *nat_addresses = data;
> + shash_destroy(&nat_addresses->nat_addresses);
> + sset_destroy(&nat_addresses->localnet_vifs);
> + sset_destroy(&nat_addresses->local_l3gw_ports);
> + sset_destroy(&nat_addresses->nat_ip_keys);
> +}
>
> /* Engine node which is used to handle the Non VIF data like
> * - OVS patch ports
> @@ -4779,6 +5092,14 @@ controller_output_bfd_chassis_handler(struct
> engine_node *node,
> return true;
> }
>
> +static bool
> +controller_output_nat_addresses_handler(struct engine_node *node,
> + void *data OVS_UNUSED)
> +{
> + engine_set_node_state(node, EN_UPDATED);
> + return true;
> +}
> +
> /* Handles sbrec_chassis changes.
> * If a new chassis is added or removed return false, so that
> * flows are recomputed. For any updates, there is no need for
> @@ -5093,6 +5414,7 @@ main(int argc, char *argv[])
> ENGINE_NODE(mac_cache, "mac_cache");
> ENGINE_NODE(bfd_chassis, "bfd_chassis");
> ENGINE_NODE(dns_cache, "dns_cache");
> + ENGINE_NODE(nat_addresses, "nat_addresses");
>
> #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR);
> SB_NODES
> @@ -5137,6 +5459,14 @@ main(int argc, char *argv[])
> engine_add_input(&en_bfd_chassis, &en_sb_chassis, NULL);
> engine_add_input(&en_bfd_chassis, &en_sb_ha_chassis_group, NULL);
>
> + engine_add_input(&en_nat_addresses, &en_ovs_open_vswitch, NULL);
> + engine_add_input(&en_nat_addresses, &en_ovs_bridge, NULL);
> + engine_add_input(&en_nat_addresses, &en_sb_chassis, NULL);
> + engine_add_input(&en_nat_addresses, &en_sb_port_binding,
> + nat_addresses_change_handler);
> + engine_add_input(&en_nat_addresses, &en_runtime_data,
> + nat_addresses_change_handler);
> +
> /* Note: The order of inputs is important, all OVS interface changes must
> * be handled before any ct_zone changes.
> */
> @@ -5300,6 +5630,8 @@ main(int argc, char *argv[])
> controller_output_mac_cache_handler);
> engine_add_input(&en_controller_output, &en_bfd_chassis,
> controller_output_bfd_chassis_handler);
> + engine_add_input(&en_controller_output, &en_nat_addresses,
> + controller_output_nat_addresses_handler);
>
> struct engine_arg engine_arg = {
> .sb_idl = ovnsb_idl_loop.idl,
> @@ -5346,6 +5678,8 @@ main(int argc, char *argv[])
> engine_get_internal_data(&en_ct_zones);
> struct ed_type_bfd_chassis *bfd_chassis_data =
> engine_get_internal_data(&en_bfd_chassis);
> + struct ed_type_nat_addresses *nat_addresses_data =
> + engine_get_internal_data(&en_nat_addresses);
> struct ed_type_runtime_data *runtime_data =
> engine_get_internal_data(&en_runtime_data);
> struct ed_type_template_vars *template_vars_data =
> @@ -5682,6 +6016,7 @@ main(int argc, char *argv[])
> }
>
> runtime_data = engine_get_data(&en_runtime_data);
> + nat_addresses_data = engine_get_data(&en_nat_addresses);
> if (runtime_data) {
> stopwatch_start(PATCH_RUN_STOPWATCH_NAME,
> time_msec());
> patch_run(ovs_idl_txn,
> @@ -5729,7 +6064,6 @@ main(int argc, char *argv[])
> pinctrl_update(ovnsb_idl_loop.idl);
> pinctrl_run(ovnsb_idl_txn,
> sbrec_datapath_binding_by_key,
> - sbrec_port_binding_by_datapath,
> sbrec_port_binding_by_key,
> sbrec_port_binding_by_name,
> sbrec_mac_binding_by_lport_ip,
> @@ -5743,13 +6077,14 @@ main(int argc, char *argv[])
> sbrec_mac_binding_table_get(
> ovnsb_idl_loop.idl),
> sbrec_bfd_table_get(ovnsb_idl_loop.idl),
> - br_int, chassis,
> + chassis,
> &runtime_data->local_datapaths,
> &runtime_data->active_tunnels,
>
> &runtime_data->local_active_ports_ipv6_pd,
> &runtime_data->local_active_ports_ras,
> ovsrec_open_vswitch_table_get(
> - ovs_idl_loop.idl));
> + ovs_idl_loop.idl),
> + nat_addresses_data);
> stopwatch_stop(PINCTRL_RUN_STOPWATCH_NAME,
> time_msec());
> mirror_run(ovs_idl_txn,
> diff --git a/controller/pinctrl.c b/controller/pinctrl.c
> index 3fb7e2fd7..e8c4ff77b 100644
> --- a/controller/pinctrl.c
> +++ b/controller/pinctrl.c
> @@ -227,14 +227,11 @@ static void destroy_send_garps_rarps(void);
> static void send_garp_rarp_wait(long long int send_garp_rarp_time);
> static void send_garp_rarp_prepare(
> struct ovsdb_idl_txn *ovnsb_idl_txn,
> - struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
> struct ovsdb_idl_index *sbrec_port_binding_by_name,
> struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> - const struct ovsrec_bridge *,
> - const struct sbrec_chassis *,
> const struct hmap *local_datapaths,
> - const struct sset *active_tunnels,
> - const struct ovsrec_open_vswitch_table *ovs_table)
> + const struct ovsrec_open_vswitch_table *ovs_table,
> + struct ed_type_nat_addresses *nat_addresses)
> OVS_REQUIRES(pinctrl_mutex);
> static void send_garp_rarp_run(struct rconn *swconn,
> long long int *send_garp_rarp_time)
> @@ -4008,7 +4005,6 @@ pinctrl_update(const struct ovsdb_idl *idl)
> void
> pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
> struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
> - struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
> struct ovsdb_idl_index *sbrec_port_binding_by_key,
> struct ovsdb_idl_index *sbrec_port_binding_by_name,
> struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> @@ -4019,13 +4015,13 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
> const struct sbrec_service_monitor_table *svc_mon_table,
> const struct sbrec_mac_binding_table *mac_binding_table,
> const struct sbrec_bfd_table *bfd_table,
> - const struct ovsrec_bridge *br_int,
> const struct sbrec_chassis *chassis,
> const struct hmap *local_datapaths,
> const struct sset *active_tunnels,
> const struct shash *local_active_ports_ipv6_pd,
> const struct shash *local_active_ports_ras,
> - const struct ovsrec_open_vswitch_table *ovs_table)
> + const struct ovsrec_open_vswitch_table *ovs_table,
> + struct ed_type_nat_addresses *nat_addresses)
> {
> ovs_mutex_lock(&pinctrl_mutex);
> run_put_mac_bindings(ovnsb_idl_txn, sbrec_datapath_binding_by_key,
> @@ -4033,10 +4029,11 @@ pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
> sbrec_mac_binding_by_lport_ip);
> run_put_vport_bindings(ovnsb_idl_txn, sbrec_datapath_binding_by_key,
> sbrec_port_binding_by_key, chassis);
> - send_garp_rarp_prepare(ovnsb_idl_txn, sbrec_port_binding_by_datapath,
> + send_garp_rarp_prepare(ovnsb_idl_txn,
> sbrec_port_binding_by_name,
> - sbrec_mac_binding_by_lport_ip, br_int, chassis,
> - local_datapaths, active_tunnels, ovs_table);
> + sbrec_mac_binding_by_lport_ip,
> + local_datapaths,
> + ovs_table, nat_addresses);
> prepare_ipv6_ras(local_active_ports_ras, sbrec_port_binding_by_name);
> prepare_ipv6_prefixd(ovnsb_idl_txn, sbrec_port_binding_by_name,
> local_active_ports_ipv6_pd, chassis,
> @@ -6175,236 +6172,6 @@ ip_mcast_querier_wait(long long int query_time)
> }
> }
>
> -/* Get localnet vifs, local l3gw ports and ofport for localnet patch ports.
> */
> -static void
> -get_localnet_vifs_l3gwports(
> - struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
> - struct ovsdb_idl_index *sbrec_port_binding_by_name,
> - const struct ovsrec_bridge *br_int,
> - const struct sbrec_chassis *chassis,
> - const struct hmap *local_datapaths,
> - struct sset *localnet_vifs,
> - struct sset *local_l3gw_ports)
> -{
> - for (int i = 0; i < br_int->n_ports; i++) {
> - const struct ovsrec_port *port_rec = br_int->ports[i];
> - if (!strcmp(port_rec->name, br_int->name)) {
> - continue;
> - }
> - const char *tunnel_id = smap_get(&port_rec->external_ids,
> - "ovn-chassis-id");
> - if (tunnel_id &&
> - encaps_tunnel_id_match(tunnel_id, chassis->name, NULL,
> NULL)) {
> - continue;
> - }
> - const char *localnet = smap_get(&port_rec->external_ids,
> - "ovn-localnet-port");
> - if (localnet) {
> - continue;
> - }
> - for (int j = 0; j < port_rec->n_interfaces; j++) {
> - const struct ovsrec_interface *iface_rec =
> port_rec->interfaces[j];
> - if (!iface_rec->n_ofport) {
> - continue;
> - }
> - /* Get localnet vif. */
> - const char *iface_id = smap_get(&iface_rec->external_ids,
> - "iface-id");
> - if (!iface_id) {
> - continue;
> - }
> - const struct sbrec_port_binding *pb
> - = lport_lookup_by_name(sbrec_port_binding_by_name, iface_id);
> - if (!pb || pb->chassis != chassis) {
> - continue;
> - }
> - if (!iface_rec->link_state ||
> - strcmp(iface_rec->link_state, "up")) {
> - continue;
> - }
> - struct local_datapath *ld
> - = get_local_datapath(local_datapaths,
> - pb->datapath->tunnel_key);
> - if (ld && ld->localnet_port) {
> - sset_add(localnet_vifs, iface_id);
> - }
> - }
> - }
> -
> - struct sbrec_port_binding *target = sbrec_port_binding_index_init_row(
> - sbrec_port_binding_by_datapath);
> -
> - const struct local_datapath *ld;
> - HMAP_FOR_EACH (ld, hmap_node, local_datapaths) {
> - const struct sbrec_port_binding *pb;
> -
> - if (!ld->localnet_port) {
> - continue;
> - }
> -
> - /* Get l3gw ports. Consider port bindings with type "l3gateway"
> - * that connect to gateway routers (if local), and consider port
> - * bindings of type "patch" since they might connect to
> - * distributed gateway ports with NAT addresses. */
> -
> - sbrec_port_binding_index_set_datapath(target, ld->datapath);
> - SBREC_PORT_BINDING_FOR_EACH_EQUAL (pb, target,
> - sbrec_port_binding_by_datapath) {
> - if ((!strcmp(pb->type, "l3gateway") && pb->chassis == chassis)
> - || !strcmp(pb->type, "patch")) {
> - sset_add(local_l3gw_ports, pb->logical_port);
> - }
> - }
> - }
> - sbrec_port_binding_index_destroy_row(target);
> -}
> -
> -
> -/* Extracts the mac, IPv4 and IPv6 addresses, and logical port from
> - * 'addresses' which should be of the format 'MAC [IP1 IP2 ..]
> - * [is_chassis_resident("LPORT_NAME")]', where IPn should be a valid IPv4
> - * or IPv6 address, and stores them in the 'ipv4_addrs' and 'ipv6_addrs'
> - * fields of 'laddrs'. The logical port name is stored in 'lport'.
> - *
> - * Returns true if at least 'MAC' is found in 'address', false otherwise.
> - *
> - * The caller must call destroy_lport_addresses() and free(*lport). */
> -static bool
> -extract_addresses_with_port(const char *addresses,
> - struct lport_addresses *laddrs,
> - char **lport)
> -{
> - int ofs;
> - if (!extract_addresses(addresses, laddrs, &ofs)) {
> - return false;
> - } else if (!addresses[ofs]) {
> - return true;
> - }
> -
> - struct lexer lexer;
> - lexer_init(&lexer, addresses + ofs);
> - lexer_get(&lexer);
> -
> - if (lexer.error || lexer.token.type != LEX_T_ID
> - || !lexer_match_id(&lexer, "is_chassis_resident")) {
> - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> - VLOG_INFO_RL(&rl, "invalid syntax '%s' in address", addresses);
> - lexer_destroy(&lexer);
> - return true;
> - }
> -
> - if (!lexer_match(&lexer, LEX_T_LPAREN)) {
> - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> - VLOG_INFO_RL(&rl, "Syntax error: expecting '(' after "
> - "'is_chassis_resident' in address '%s'",
> addresses);
> - lexer_destroy(&lexer);
> - return false;
> - }
> -
> - if (lexer.token.type != LEX_T_STRING) {
> - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> - VLOG_INFO_RL(&rl,
> - "Syntax error: expecting quoted string after "
> - "'is_chassis_resident' in address '%s'", addresses);
> - lexer_destroy(&lexer);
> - return false;
> - }
> -
> - *lport = xstrdup(lexer.token.s);
> -
> - lexer_get(&lexer);
> - if (!lexer_match(&lexer, LEX_T_RPAREN)) {
> - static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
> - VLOG_INFO_RL(&rl, "Syntax error: expecting ')' after quoted string
> in "
> - "'is_chassis_resident()' in address '%s'",
> - addresses);
> - lexer_destroy(&lexer);
> - return false;
> - }
> -
> - lexer_destroy(&lexer);
> - return true;
> -}
> -
> -static void
> -consider_nat_address(struct ovsdb_idl_index *sbrec_port_binding_by_name,
> - const char *nat_address,
> - const struct sbrec_port_binding *pb,
> - struct sset *nat_address_keys,
> - const struct sbrec_chassis *chassis,
> - const struct sset *active_tunnels,
> - struct shash *nat_addresses)
> -{
> - struct lport_addresses *laddrs = xmalloc(sizeof *laddrs);
> - char *lport = NULL;
> - if (!extract_addresses_with_port(nat_address, laddrs, &lport)
> - || (!lport && !strcmp(pb->type, "patch"))
> - || (lport && !lport_is_chassis_resident(
> - sbrec_port_binding_by_name, chassis,
> - active_tunnels, lport))) {
> - destroy_lport_addresses(laddrs);
> - free(laddrs);
> - free(lport);
> - return;
> - }
> - free(lport);
> -
> - int i;
> - for (i = 0; i < laddrs->n_ipv4_addrs; i++) {
> - char *name = xasprintf("%s-%s", pb->logical_port,
> - laddrs->ipv4_addrs[i].addr_s);
> - sset_add(nat_address_keys, name);
> - free(name);
> - }
> - if (laddrs->n_ipv4_addrs == 0) {
> - char *name = xasprintf("%s-noip", pb->logical_port);
> - sset_add(nat_address_keys, name);
> - free(name);
> - }
> - shash_add(nat_addresses, pb->logical_port, laddrs);
> -}
> -
> -static void
> -get_nat_addresses_and_keys(struct ovsdb_idl_index
> *sbrec_port_binding_by_name,
> - struct sset *nat_address_keys,
> - struct sset *local_l3gw_ports,
> - const struct sbrec_chassis *chassis,
> - const struct sset *active_tunnels,
> - struct shash *nat_addresses)
> -{
> - const char *gw_port;
> - SSET_FOR_EACH(gw_port, local_l3gw_ports) {
> - const struct sbrec_port_binding *pb;
> -
> - pb = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
> - if (!pb) {
> - continue;
> - }
> -
> - if (pb->n_nat_addresses) {
> - for (int i = 0; i < pb->n_nat_addresses; i++) {
> - consider_nat_address(sbrec_port_binding_by_name,
> - pb->nat_addresses[i], pb,
> - nat_address_keys, chassis,
> - active_tunnels,
> - nat_addresses);
> - }
> - } else {
> - /* Continue to support options:nat-addresses for version
> - * upgrade. */
> - const char *nat_addresses_options = smap_get(&pb->options,
> - "nat-addresses");
> - if (nat_addresses_options) {
> - consider_nat_address(sbrec_port_binding_by_name,
> - nat_addresses_options, pb,
> - nat_address_keys, chassis,
> - active_tunnels,
> - nat_addresses);
> - }
> - }
> - }
> -}
> -
> static void
> send_garp_rarp_wait(long long int send_garp_rarp_time)
> {
> @@ -6441,96 +6208,70 @@ send_garp_rarp_run(struct rconn *swconn, long long
> int *send_garp_rarp_time)
> * thread context. */
> static void
> send_garp_rarp_prepare(struct ovsdb_idl_txn *ovnsb_idl_txn,
> - struct ovsdb_idl_index
> *sbrec_port_binding_by_datapath,
> struct ovsdb_idl_index *sbrec_port_binding_by_name,
> struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> - const struct ovsrec_bridge *br_int,
> - const struct sbrec_chassis *chassis,
> const struct hmap *local_datapaths,
> - const struct sset *active_tunnels,
> - const struct ovsrec_open_vswitch_table *ovs_table)
> + const struct ovsrec_open_vswitch_table *ovs_table,
> + struct ed_type_nat_addresses *nat_addresses)
> OVS_REQUIRES(pinctrl_mutex)
> {
> - struct sset localnet_vifs = SSET_INITIALIZER(&localnet_vifs);
> - struct sset local_l3gw_ports = SSET_INITIALIZER(&local_l3gw_ports);
> - struct sset nat_ip_keys = SSET_INITIALIZER(&nat_ip_keys);
> - struct shash nat_addresses;
> - unsigned long long garp_max_timeout = GARP_RARP_DEF_MAX_TIMEOUT;
> - bool garp_continuous = false;
> - const struct ovsrec_open_vswitch *cfg =
> - ovsrec_open_vswitch_table_first(ovs_table);
> - if (cfg) {
> - garp_max_timeout = smap_get_ullong(
> - &cfg->external_ids, "garp-max-timeout-sec", 0) * 1000;
> - garp_continuous = !!garp_max_timeout;
> - if (!garp_max_timeout) {
> - garp_max_timeout = GARP_RARP_DEF_MAX_TIMEOUT;
> - }
> - }
> -
> - shash_init(&nat_addresses);
> -
> - get_localnet_vifs_l3gwports(sbrec_port_binding_by_datapath,
> - sbrec_port_binding_by_name,
> - br_int, chassis, local_datapaths,
> - &localnet_vifs, &local_l3gw_ports);
> -
> - get_nat_addresses_and_keys(sbrec_port_binding_by_name,
> - &nat_ip_keys, &local_l3gw_ports,
> - chassis, active_tunnels,
> - &nat_addresses);
> - /* For deleted ports and deleted nat ips, remove from
> - * send_garp_rarp_data. */
> - struct shash_node *iter;
> - SHASH_FOR_EACH_SAFE (iter, &send_garp_rarp_data) {
> - if (!sset_contains(&localnet_vifs, iter->name) &&
> - !sset_contains(&nat_ip_keys, iter->name)) {
> - send_garp_rarp_delete(iter->name);
> + if (nat_addresses) {
> + unsigned long long garp_max_timeout = GARP_RARP_DEF_MAX_TIMEOUT;
> + bool garp_continuous = false;
> +
> + const struct ovsrec_open_vswitch *cfg =
> + ovsrec_open_vswitch_table_first(ovs_table);
> + if (cfg) {
> + garp_max_timeout = smap_get_ullong(
> + &cfg->external_ids, "garp-max-timeout-sec", 0) * 1000;
> + garp_continuous = !!garp_max_timeout;
> + if (!garp_max_timeout) {
> + garp_max_timeout = GARP_RARP_DEF_MAX_TIMEOUT;
> + }
> }
> - }
> -
> - /* Update send_garp_rarp_data. */
> - const char *iface_id;
> - SSET_FOR_EACH (iface_id, &localnet_vifs) {
> - const struct sbrec_port_binding *pb = lport_lookup_by_name(
> - sbrec_port_binding_by_name, iface_id);
> - if (pb && !smap_get_bool(&pb->options, "disable_garp_rarp", false)) {
> - send_garp_rarp_update(ovnsb_idl_txn,
> - sbrec_mac_binding_by_lport_ip,
> - local_datapaths, pb, &nat_addresses,
> - garp_max_timeout, garp_continuous);
> + /* For deleted ports and deleted nat ips, remove from
> + * send_garp_rarp_data. */
> + struct shash_node *iter;
> + SHASH_FOR_EACH_SAFE (iter, &send_garp_rarp_data) {
> + if (!sset_contains(&nat_addresses->localnet_vifs, iter->name) &&
> + !sset_contains(&nat_addresses->nat_ip_keys, iter->name)) {
> + send_garp_rarp_delete(iter->name);
> + }
> }
> - }
> -
> - /* Update send_garp_rarp_data for nat-addresses. */
> - const char *gw_port;
> - SSET_FOR_EACH (gw_port, &local_l3gw_ports) {
> - const struct sbrec_port_binding *pb
> - = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
> - if (pb && !smap_get_bool(&pb->options, "disable_garp_rarp", false)) {
> - send_garp_rarp_update(ovnsb_idl_txn,
> sbrec_mac_binding_by_lport_ip,
> - local_datapaths, pb, &nat_addresses,
> - garp_max_timeout, garp_continuous);
> + /* Update send_garp_rarp_data. */
> + const char *iface_id;
> + SSET_FOR_EACH (iface_id, &nat_addresses->localnet_vifs) {
> + const struct sbrec_port_binding *pb = lport_lookup_by_name(
> + sbrec_port_binding_by_name, iface_id);
> + if (pb && !smap_get_bool(
> + &pb->options, "disable_garp_rarp", false)) {
> + send_garp_rarp_update(ovnsb_idl_txn,
> + sbrec_mac_binding_by_lport_ip,
> + local_datapaths, pb,
> + &nat_addresses->nat_addresses,
> + garp_max_timeout, garp_continuous);
> + }
> }
> - }
>
> - /* pinctrl_handler thread will send the GARPs. */
> -
> - sset_destroy(&localnet_vifs);
> - sset_destroy(&local_l3gw_ports);
> + /* Update send_garp_rarp_data for nat-addresses. */
> + const char *gw_port;
> + SSET_FOR_EACH (gw_port, &nat_addresses->local_l3gw_ports) {
> + const struct sbrec_port_binding *pb
> + = lport_lookup_by_name(sbrec_port_binding_by_name, gw_port);
> + if (pb && !smap_get_bool(&pb->options, "disable_garp_rarp",
> + false)) {
> + send_garp_rarp_update(ovnsb_idl_txn,
> + sbrec_mac_binding_by_lport_ip,
> + local_datapaths, pb,
> + &nat_addresses->nat_addresses,
> + garp_max_timeout, garp_continuous);
> + }
> + }
>
> - SHASH_FOR_EACH_SAFE (iter, &nat_addresses) {
> - struct lport_addresses *laddrs = iter->data;
> - destroy_lport_addresses(laddrs);
> - shash_delete(&nat_addresses, iter);
> - free(laddrs);
> + /* pinctrl_handler thread will send the GARPs. */
> + garp_rarp_max_timeout = garp_max_timeout;
> + garp_rarp_continuous = garp_continuous;
> }
> - shash_destroy(&nat_addresses);
> -
> - sset_destroy(&nat_ip_keys);
> -
> - garp_rarp_max_timeout = garp_max_timeout;
> - garp_rarp_continuous = garp_continuous;
> }
>
> static bool
> diff --git a/controller/pinctrl.h b/controller/pinctrl.h
> index 846afe0a4..c6a7423b8 100644
> --- a/controller/pinctrl.h
> +++ b/controller/pinctrl.h
> @@ -20,6 +20,7 @@
> #include <stdint.h>
>
> #include "lib/sset.h"
> +#include "openvswitch/shash.h"
> #include "openvswitch/list.h"
> #include "openvswitch/meta-flow.h"
>
> @@ -39,10 +40,16 @@ struct sbrec_bfd_table;
> struct sbrec_port_binding;
> struct sbrec_mac_binding_table;
>
> +struct ed_type_nat_addresses {
> + struct shash nat_addresses;
> + struct sset localnet_vifs;
> + struct sset local_l3gw_ports;
> + struct sset nat_ip_keys;
> +};
> +
> void pinctrl_init(void);
> void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
> struct ovsdb_idl_index *sbrec_datapath_binding_by_key,
> - struct ovsdb_idl_index *sbrec_port_binding_by_datapath,
> struct ovsdb_idl_index *sbrec_port_binding_by_key,
> struct ovsdb_idl_index *sbrec_port_binding_by_name,
> struct ovsdb_idl_index *sbrec_mac_binding_by_lport_ip,
> @@ -53,12 +60,13 @@ void pinctrl_run(struct ovsdb_idl_txn *ovnsb_idl_txn,
> const struct sbrec_service_monitor_table *,
> const struct sbrec_mac_binding_table *,
> const struct sbrec_bfd_table *,
> - const struct ovsrec_bridge *, const struct sbrec_chassis *,
> + const struct sbrec_chassis *,
> const struct hmap *local_datapaths,
> const struct sset *active_tunnels,
> const struct shash *local_active_ports_ipv6_pd,
> const struct shash *local_active_ports_ras,
> - const struct ovsrec_open_vswitch_table *ovs_table);
> + const struct ovsrec_open_vswitch_table *ovs_table,
> + struct ed_type_nat_addresses *nat_addresses);
> void pinctrl_wait(struct ovsdb_idl_txn *ovnsb_idl_txn);
> void pinctrl_destroy(void);
>
> --
> 2.43.0
>
>
> _______________________________________________
> dev mailing list
> [email protected]
> https://mail.openvswitch.org/mailman/listinfo/ovs-dev
_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev