On 3/28/23 10:12, Ales Musil wrote:
> Add node that will hold data about recently added
> MAC bindings. This node will be used later on to prevent
> race condition in packet buffering. the MAC binding is
> kept in the node longer than the timeout of the buffered
> packet to make sure that we don't miss it.
> 
> Signed-off-by: Ales Musil <[email protected]>
> ---
> v4: Rebase on top of current main.
>     Split into three patches.
> ---
>  controller/ovn-controller.c | 201 ++++++++++++++++++++++++++++++++++++
>  1 file changed, 201 insertions(+)
> 
> diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c
> index 76be2426e..d465f00e9 100644
> --- a/controller/ovn-controller.c
> +++ b/controller/ovn-controller.c
> @@ -45,6 +45,7 @@
>  #include "lib/vswitch-idl.h"
>  #include "local_data.h"
>  #include "lport.h"
> +#include "mac-learn.h"
>  #include "memory.h"
>  #include "ofctrl.h"
>  #include "ofctrl-seqno.h"
> @@ -4303,6 +4304,185 @@ pflow_output_debug_handler(struct engine_node *node, 
> void *data)
>      return true;
>  }
>  
> +static void
> +recent_mac_bindings_add(struct hmap *recent_mbs,
> +                        const struct sbrec_mac_binding *smb,
> +                        const struct hmap *local_datapaths,
> +                        struct ovsdb_idl_index *sbrec_port_binding_by_name)
> +{

This function is extremely similar with the body of the loop in
run_buffered_binding() in pinctrl.  Can we find a way to avoid the code
duplication?

After reading patch 3/3 I realized you actually do something like that
there.  That's indication to me that patches 2/3 and 3/3 should actually
be squashed.  It was also unclear to me from the current patch 2/3 log
why we need these recent mac bindings.

Also, should we add an API to the mac_binding_map structure I suggested
for patch 1/3 to insert an entry that's built from a sbrec_mac_binding?

> +    ovs_be32 ip4;
> +    struct in6_addr ip;
> +    struct eth_addr mac;
> +    const struct sbrec_port_binding *pb;
> +
> +    if (!get_local_datapath(local_datapaths, smb->datapath->tunnel_key)) {
> +        return;
> +    }
> +
> +    pb = lport_lookup_by_name(sbrec_port_binding_by_name, smb->logical_port);
> +    if (!pb) {
> +        return;
> +    }
> +
> +    if (!eth_addr_from_string(smb->mac, &mac)) {
> +        return;
> +    }
> +
> +    if (strchr(smb->ip, '.')) {
> +        if (!ip_parse(smb->ip, &ip4)) {
> +            return;
> +        }
> +        ip = in6_addr_mapped_ipv4(ip4);
> +    } else {
> +        if (!ipv6_parse(smb->ip, &ip)) {
> +            return;
> +        }
> +    }

Given that you refactor so much in patch 1/3 already, can you please
also add a patch that adds a new ovn-util.c function to parse IPs and
hides the strchr(.., '.')?  We do that in a few places already and it's
a bit annoying to see the same code everywhere.

> +
> +    /* Give the recent mac_binding entry bigger timeout than the buffered
> +     * packet in case the MAC binding is created earlier. */
> +    ovn_mac_binding_add(recent_mbs, smb->datapath->tunnel_key, 
> pb->tunnel_key,
> +                        &ip, mac, 2 * OVN_BUFFERED_PACKETS_TIMEOUT, false);
> +
> +    const char *redirect_port =
> +        smap_get(&pb->options, "chassis-redirect-port");
> +    if (!redirect_port) {
> +        return;
> +    }
> +
> +    pb = lport_lookup_by_name(sbrec_port_binding_by_name, redirect_port);
> +    if (!pb || pb->datapath->tunnel_key != smb->datapath->tunnel_key ||
> +        strcmp(pb->type, "chassisredirect")) {
> +        return;
> +    }
> +
> +    /* Add the same entry also for chassisredirect port as the buffered 
> traffic
> +     * might be buffered on the cr port. */
> +    ovn_mac_binding_add(recent_mbs, smb->datapath->tunnel_key, 
> pb->tunnel_key,
> +                        &ip, mac, 2 * OVN_BUFFERED_PACKETS_TIMEOUT, false);
> +}
> +
> +static void *
> +en_recent_mac_bindings_init(struct engine_node *node OVS_UNUSED,
> +                            struct engine_arg *arg OVS_UNUSED)
> +{
> +    struct hmap *recent_mbs = xmalloc(sizeof *recent_mbs);
> +    hmap_init(recent_mbs);
> +
> +    return recent_mbs;
> +}
> +
> +static void
> +en_recent_mac_bindings_cleanup(void *data)
> +{
> +    struct hmap *recent_mbs = data;
> +    ovn_mac_bindings_destroy(recent_mbs);
> +}
> +
> +static void
> +en_recent_mac_bindings_clear_tracked_data(void *data)
> +{
> +    long long now = time_msec();
> +    struct hmap *recent_mbs = data;
> +
> +    struct mac_binding *mb;
> +    HMAP_FOR_EACH_SAFE (mb, hmap_node, recent_mbs) {
> +        if (ovn_mac_binding_is_expired(mb, now)) {
> +            ovn_mac_binding_remove(mb, recent_mbs);
> +        }
> +    }
> +}
> +
> +static void
> +en_recent_mac_bindings_run(struct engine_node *node, void *data)
> +{
> +    struct hmap *recent_mbs = data;
> +    struct ed_type_runtime_data *rt_data =
> +        engine_get_input_data("runtime_data", node);
> +    const struct sbrec_mac_binding_table *mac_binding_table =
> +        EN_OVSDB_GET(engine_get_input("SB_mac_binding", node));
> +    struct ovsdb_idl_index *sbrec_port_binding_by_name =
> +        engine_ovsdb_node_get_index(
> +            engine_get_input("SB_port_binding", node),
> +            "name");
> +
> +    const struct sbrec_mac_binding *smb;
> +    SBREC_MAC_BINDING_TABLE_FOR_EACH (smb, mac_binding_table) {
> +        recent_mac_bindings_add(recent_mbs, smb, &rt_data->local_datapaths,
> +                                sbrec_port_binding_by_name);
> +    }
> +}
> +
> +static bool
> +recent_mac_bindings_mac_binding_handler(struct engine_node *node, void *data)
> +{
> +    struct hmap *recent_mbs = data;
> +    struct ed_type_runtime_data *rt_data =
> +        engine_get_input_data("runtime_data", node);
> +    const struct sbrec_mac_binding_table *mac_binding_table =
> +        EN_OVSDB_GET(engine_get_input("SB_mac_binding", node));
> +    struct ovsdb_idl_index *sbrec_port_binding_by_name =
> +        engine_ovsdb_node_get_index(
> +            engine_get_input("SB_port_binding", node),
> +            "name");
> +
> +    const struct sbrec_mac_binding *smb;
> +    SBREC_MAC_BINDING_TABLE_FOR_EACH_TRACKED (smb, mac_binding_table) {
> +        /* The deleted entry will expire eventually. */
> +        if (sbrec_mac_binding_is_deleted(smb)) {
> +            continue;
> +        }
> +
> +        recent_mac_bindings_add(recent_mbs, smb, &rt_data->local_datapaths,
> +                                sbrec_port_binding_by_name);
> +    }
> +
> +    engine_set_node_state(node, EN_UPDATED);
> +    return true;
> +}
> +
> +static bool
> +recent_mac_bindings_runtime_data_handler(struct engine_node *node, void 
> *data)
> +{
> +    struct hmap *recent_mbs = data;
> +    struct ed_type_runtime_data *rt_data =
> +        engine_get_input_data("runtime_data", node);
> +    struct ovsdb_idl_index *smb_by_datapath =
> +        engine_ovsdb_node_get_index(
> +            engine_get_input("SB_mac_binding", node),
> +            "datapath");
> +    struct ovsdb_idl_index *sbrec_port_binding_by_name =
> +        engine_ovsdb_node_get_index(
> +            engine_get_input("SB_port_binding", node),
> +            "name");
> +
> +    if (!rt_data->tracked) {
> +        return false;
> +    }
> +
> +    struct tracked_datapath *tdp;
> +    HMAP_FOR_EACH (tdp, node, &rt_data->tracked_dp_bindings) {
> +        if (tdp->tracked_type != TRACKED_RESOURCE_NEW) {
> +            continue;
> +        }
> +
> +        struct sbrec_mac_binding *mb_index_row =
> +            sbrec_mac_binding_index_init_row(smb_by_datapath);
> +        sbrec_mac_binding_index_set_datapath(mb_index_row, tdp->dp);
> +
> +        const struct sbrec_mac_binding *smb;
> +        SBREC_MAC_BINDING_FOR_EACH_EQUAL (smb, mb_index_row, 
> smb_by_datapath) {
> +            recent_mac_bindings_add(recent_mbs, smb, 
> &rt_data->local_datapaths,
> +                                    sbrec_port_binding_by_name);
> +        }
> +
> +        sbrec_mac_binding_index_destroy_row(mb_index_row);
> +    }
> +
> +    engine_set_node_state(node, EN_UPDATED);
> +    return true;
> +}
> +
>  static void *
>  en_controller_output_init(struct engine_node *node OVS_UNUSED,
>                            struct engine_arg *arg OVS_UNUSED)
> @@ -4339,6 +4519,14 @@ controller_output_lflow_output_handler(struct 
> engine_node *node,
>      return true;
>  }
>  
> +static bool
> +flow_output_recent_mac_bindings_handler(struct engine_node *node,
> +                                        void *data OVS_UNUSED)
> +{
> +    engine_set_node_state(node, EN_UPDATED);
> +    return true;
> +}
> +
>  struct ovn_controller_exit_args {
>      bool *exiting;
>      bool *restart;
> @@ -4611,6 +4799,8 @@ main(int argc, char *argv[])
>      ENGINE_NODE(northd_options, "northd_options");
>      ENGINE_NODE(dhcp_options, "dhcp_options");
>      ENGINE_NODE_WITH_CLEAR_TRACK_DATA(lb_data, "lb_data");
> +    ENGINE_NODE_WITH_CLEAR_TRACK_DATA(recent_mac_bindings,
> +                                      "recent_mac_bindings");
>  
>  #define SB_NODE(NAME, NAME_STR) ENGINE_NODE_SB(NAME, NAME_STR);
>      SB_NODES
> @@ -4783,10 +4973,21 @@ main(int argc, char *argv[])
>      engine_add_input(&en_runtime_data, &en_ovs_interface_shadow,
>                       runtime_data_ovs_interface_shadow_handler);
>  
> +    engine_add_input(&en_recent_mac_bindings, &en_sb_mac_binding,
> +                     recent_mac_bindings_mac_binding_handler);
> +    engine_add_input(&en_recent_mac_bindings, &en_runtime_data,
> +                     recent_mac_bindings_runtime_data_handler);
> +    /* Using a noop handler since we really need just access to the index
> +     * which allows us to filter port binding by name. */
> +    engine_add_input(&en_recent_mac_bindings, &en_sb_port_binding,
> +                     engine_noop_handler);
> +
>      engine_add_input(&en_controller_output, &en_lflow_output,
>                       controller_output_lflow_output_handler);
>      engine_add_input(&en_controller_output, &en_pflow_output,
>                       controller_output_pflow_output_handler);
> +    engine_add_input(&en_controller_output, &en_recent_mac_bindings,
> +                     flow_output_recent_mac_bindings_handler);
>  
>      struct engine_arg engine_arg = {
>          .sb_idl = ovnsb_idl_loop.idl,

Thanks,
Dumitru

_______________________________________________
dev mailing list
[email protected]
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to