On Fri, Dec 24, 2021 at 6:50 AM Lorenzo Bianconi <[email protected]> wrote: > > > From: Karthik Chandrashekar <[email protected]> > > > > Add a new NB and SB table for managing Static MAC_Binding entries. > > This table is currently supported for logical routers. OVN northd > > is responsible for propagating the values from NB to SB. OVN controller > > is responsible for installation MAC lookup flows. The priority of > > the installed flows are based on override_dynamic_mac flag. This helps > > control the precedence of statically programmed vs dynamically learnt > > MAC Bindings. > > Hi Karthik, > > thx for working on this :) > I like the new approch, I added some comments inline. > > Regards, > Lorenzo
Hi Karthik, The ddlog code is out of sync with the northd c code for a while. If you want you can skip the ddlog part for now. Numan > > > > > Signed-off-by: Karthik Chandrashekar <[email protected]> > > --- > > controller/lflow.c | 107 +++++++++++++----- > > controller/lflow.h | 10 +- > > controller/ovn-controller.c | 37 ++++++- > > lib/automake.mk | 2 + > > lib/static-mac-binding-index.c | 43 ++++++++ > > lib/static-mac-binding-index.h | 27 +++++ > > northd/en-northd.c | 8 ++ > > northd/inc-proc-northd.c | 14 ++- > > northd/northd.c | 75 +++++++++++++ > > northd/northd.h | 3 + > > ovn-nb.ovsschema | 15 ++- > > ovn-nb.xml | 29 +++++ > > ovn-sb.ovsschema | 14 ++- > > ovn-sb.xml | 27 +++++ > > tests/ovn-nbctl.at | 69 ++++++++++++ > > tests/ovn-northd.at | 24 ++++ > > tests/ovn.at | 90 +++++++++++++++ > > utilities/ovn-nbctl.c | 193 ++++++++++++++++++++++++++++++++- > > 18 files changed, 748 insertions(+), 39 deletions(-) > > create mode 100644 lib/static-mac-binding-index.c > > create mode 100644 lib/static-mac-binding-index.h > > > > diff --git a/controller/lflow.c b/controller/lflow.c > > index 933e2f3cc..c86d35960 100644 > > --- a/controller/lflow.c > > +++ b/controller/lflow.c > > @@ -1030,40 +1030,50 @@ static void > > consider_neighbor_flow(struct ovsdb_idl_index *sbrec_port_binding_by_name, > > const struct hmap *local_datapaths, > > const struct sbrec_mac_binding *b, > > - struct ovn_desired_flow_table *flow_table) > > + const struct sbrec_static_mac_binding *smb, > > + struct ovn_desired_flow_table *flow_table, > > + uint16_t priority) > > IIUC the code, doing so we will end-up having one entry for the dynamic > learned mac > (with lower priority) and one for the static mac binding (with higher > priority). Is it correct? > If so I guess we should just avoid adding the dynamic binding if we have > configured > a static one (and overwrite it if it occurs in the reverse order). > > [...] > > +static const struct nbrec_static_mac_binding * > > +static_mac_binding_by_port_ip(struct northd_input *input_data, > > + const char *logical_port, const char *ip) > > +{ > > + const struct nbrec_static_mac_binding *nb_smb = NULL; > > + > > + NBREC_STATIC_MAC_BINDING_TABLE_FOR_EACH ( > > + nb_smb, input_data->nbrec_static_mac_binding_table) { > > + if (!strcmp(nb_smb->logical_port, logical_port) && > > + !strcmp(nb_smb->ip, ip)) { > > + break; > > + } > > + } > > It seems we have 2 copies of a lookup-by-ip routine (one here) and one for > ovn-nbctl. Can we please unify the code? > Moreover can you please run checkpatch.py? > > > + > > + return nb_smb; > > +} > > + > > +static void > > +build_static_mac_binding_table(struct northd_input *input_data, > > + struct ovsdb_idl_txn *ovnsb_txn, > > + struct hmap *ports) > > +{ > > + /* Cleanup SB Static_MAC_Binding entries which do not have > > corresponding > > + * NB Static_MAC_Binding entries. */ > > + const struct nbrec_static_mac_binding *nb_smb; > > + const struct sbrec_static_mac_binding *sb_smb, *sb_smb_next; > > + SBREC_STATIC_MAC_BINDING_TABLE_FOR_EACH_SAFE (sb_smb, sb_smb_next, > > + input_data->sbrec_static_mac_binding_table) { > > + nb_smb = static_mac_binding_by_port_ip(input_data, > > sb_smb->logical_port, > > + sb_smb->ip); > > + if (!nb_smb) { > > + sbrec_static_mac_binding_delete(sb_smb); > > + } > > + } > > + > > + /* Create/Update SB Static_MAC_Binding entries with corresponding > > values > > + * from NB Static_MAC_Binding entries. */ > > + NBREC_STATIC_MAC_BINDING_TABLE_FOR_EACH ( > > + nb_smb, input_data->nbrec_static_mac_binding_table) { > > + struct ovn_port *op = ovn_port_find(ports, nb_smb->logical_port); > > + if (op && op->nbrp) { > > + struct ovn_datapath *od = op->od; > > + if (od && od->sb) { > > + const struct sbrec_static_mac_binding *mb = > > + static_mac_binding_lookup( > > + input_data->sbrec_static_mac_binding_by_lport_ip, > > + nb_smb->logical_port, nb_smb->ip); > > + if (!mb) { > > + /* Create new entry */ > > + mb = sbrec_static_mac_binding_insert(ovnsb_txn); > > + sbrec_static_mac_binding_set_logical_port( > > + mb, nb_smb->logical_port); > > + sbrec_static_mac_binding_set_ip(mb, nb_smb->ip); > > + sbrec_static_mac_binding_set_mac(mb, nb_smb->mac); > > + sbrec_static_mac_binding_set_override_dynamic_mac(mb, > > + nb_smb->override_dynamic_mac); > > + sbrec_static_mac_binding_set_datapath(mb, od->sb); > > + } else { > > + /* Update existing entry if there is a change*/ > > + if (strcmp(mb->mac, nb_smb->mac)) { > > + sbrec_static_mac_binding_set_mac(mb, nb_smb->mac); > > + } > > + if (mb->override_dynamic_mac != > > + nb_smb->override_dynamic_mac) { > > + > > sbrec_static_mac_binding_set_override_dynamic_mac(mb, > > + nb_smb->override_dynamic_mac); > > + } > > + } > > + } > > + } > > + } > > +} > > + > > void > > [...] > > @@ -5697,6 +5704,175 @@ nbctl_lrp_get_redirect_type(struct ctl_context *ctx) > > !redirect_type ? "overlay": redirect_type); > > } > > > > +static const struct nbrec_static_mac_binding * > > +static_mac_binding_by_port_ip(struct ctl_context *ctx, > > + const char *logical_port, const char *ip) > > +{ > > + const struct nbrec_static_mac_binding *nb_smb = NULL; > > + > > + NBREC_STATIC_MAC_BINDING_FOR_EACH(nb_smb, ctx->idl) { > > + if (!strcmp(nb_smb->logical_port, logical_port) && > > + !strcmp(nb_smb->ip, ip)) { > > + break; > > + } > > ditto. > > > + } > > + > > + return nb_smb; > > +} > > + > > +static void > > +nbctl_pre_static_mac_binding_add(struct ctl_context *ctx) > > +{ > > + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name); > > + > > + ovsdb_idl_add_column(ctx->idl, > > &nbrec_static_mac_binding_col_logical_port); > > + ovsdb_idl_add_column(ctx->idl, &nbrec_static_mac_binding_col_ip); > > + ovsdb_idl_add_column(ctx->idl, &nbrec_static_mac_binding_col_mac); > > +} > > + > > +static void > > +nbctl_static_mac_binding_add(struct ctl_context *ctx) > > +{ > > + const char *logical_port = ctx->argv[1]; > > + const char *ip = ctx->argv[2]; > > + const char *mac = ctx->argv[3]; > > + char *new_ip = NULL; > > + > > + const struct nbrec_logical_router_port *lrp; > > + char *error = lrp_by_name_or_uuid(ctx, logical_port, true, &lrp); > > + if (error) { > > + ctx->error = error; > > + goto cleanup; > > I guess you can just return here. > > > + } > > + > > + new_ip = normalize_addr_str(ip); > > + if (!new_ip) { > > + ctl_error(ctx, "%s: Not a valid IPv4 or IPv6 address.", ip); > > + return; > > + } > > + > > + struct eth_addr ea; > > + if (!eth_addr_from_string(mac, &ea)) { > > + ctl_error(ctx, "invalid mac address %s.", mac); > > + goto cleanup; > > + } > > + > > + bool may_exist = shash_find(&ctx->options, "--may-exist") != NULL; > > + const struct nbrec_static_mac_binding *nb_smb = > > + static_mac_binding_by_port_ip(ctx, logical_port, ip); > > + if (nb_smb) { > > + char *old_ip; > > + bool should_return = false; > > + old_ip = normalize_addr_str(nb_smb->ip); > > + > > + if (!strcmp(nb_smb->logical_port, logical_port)) { > > + if (!strcmp(old_ip, new_ip)) { > > Have we already checked "logical_port" and "new_ip" during the lookup? > > > + if (may_exist) { > > + nbrec_static_mac_binding_verify_mac(nb_smb); > > + nbrec_static_mac_binding_set_mac(nb_smb, mac); > > + should_return = true; > > + } else { > > + ctl_error(ctx, "%s, %s: a Static_MAC_Binding with this > > " > > + "logical_port and ip already exists", > > + logical_port, new_ip); > > + should_return = true; > > + } > > + } > > + } > > + free(old_ip); > > + if (should_return) { > > + goto cleanup; > > + } > > + } > > + > > + /* Create Static_MAC_Binding entry */ > > + nb_smb = nbrec_static_mac_binding_insert(ctx->txn); > > + nbrec_static_mac_binding_set_logical_port(nb_smb, logical_port); > > + nbrec_static_mac_binding_set_ip(nb_smb, new_ip); > > + nbrec_static_mac_binding_set_mac(nb_smb, mac); > > + > > +cleanup: > > + free(new_ip); > > +} > > + > > +static void > > +nbctl_pre_static_mac_binding_del(struct ctl_context *ctx) > > +{ > > + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_port_col_name); > > + > > + ovsdb_idl_add_column(ctx->idl, > > &nbrec_static_mac_binding_col_logical_port); > > + ovsdb_idl_add_column(ctx->idl, &nbrec_static_mac_binding_col_ip); > > + ovsdb_idl_add_column(ctx->idl, &nbrec_static_mac_binding_col_mac); > > +} > > + > > +static void > > +nbctl_static_mac_binding_del(struct ctl_context *ctx) > > +{ > > + bool must_exist = !shash_find(&ctx->options, "--if-exists"); > > + const char *logical_port = ctx->argv[1]; > > + const struct nbrec_logical_router_port *lrp; > > + char *error = lrp_by_name_or_uuid(ctx, logical_port, true, &lrp); > > + if (error) { > > + ctx->error = error; > > + return; > > + } > > + > > + char *ip = normalize_addr_str(ctx->argv[2]); > > + if (!ip) { > > + ctl_error(ctx, "%s: Not a valid IPv4 or IPv6 address.", > > ctx->argv[2]); > > + return; > > + } > > + > > + const struct nbrec_static_mac_binding *nb_smb = > > + static_mac_binding_by_port_ip(ctx, logical_port, ip); > > + > > + if (nb_smb) { > > + /* Remove the matching Static_MAC_Binding. */ > > + nbrec_static_mac_binding_delete(nb_smb); > > + goto cleanup; > > + } > > + > > + if (must_exist) { > > + ctl_error(ctx, "no matching Static_MAC_Binding with port %s and ip > > %s", > > + logical_port, ip); > > + } > > + > > +cleanup: > > + free(ip); > > +} > > + > > +static void > > +nbctl_pre_static_mac_binding_list(struct ctl_context *ctx) > > +{ > > + ovsdb_idl_add_column(ctx->idl, &nbrec_logical_router_col_name); > > + > > + ovsdb_idl_add_column(ctx->idl, > > &nbrec_static_mac_binding_col_logical_port); > > + ovsdb_idl_add_column(ctx->idl, &nbrec_static_mac_binding_col_ip); > > + ovsdb_idl_add_column(ctx->idl, &nbrec_static_mac_binding_col_mac); > > +} > > + > > +static void > > +nbctl_static_mac_binding_list(struct ctl_context *ctx) > > +{ > > + struct smap lr_mac_bindings = SMAP_INITIALIZER(&lr_mac_bindings); > > + const struct nbrec_static_mac_binding *nb_smb = NULL; > > + NBREC_STATIC_MAC_BINDING_FOR_EACH(nb_smb, ctx->idl) { > > + char *key = xasprintf("%-25s%-25s", nb_smb->logical_port, > > nb_smb->ip); > > + smap_add_format(&lr_mac_bindings, key, "%s", nb_smb->mac); > > + free(key); > > + } > > + > > + const struct smap_node **nodes = smap_sort(&lr_mac_bindings); > > + if (nodes) { > > + ds_put_format(&ctx->output, "%-25s%-25s%s\n", > > + "LOGICAL_PORT", "IP", "MAC"); > > + for (size_t i = 0; i < smap_count(&lr_mac_bindings); i++) { > > + const struct smap_node *node = nodes[i]; > > + ds_put_format(&ctx->output, "%-25s%s\n", node->key, > > node->value); > > + } > > + } > > +} > > + > > static const struct nbrec_forwarding_group * > > fwd_group_by_name_or_uuid(struct ctl_context *ctx, const char *id) > > { > > @@ -7198,6 +7374,17 @@ static const struct ctl_command_syntax > > nbctl_commands[] = { > > pre_ha_ch_grp_set_chassis_prio, cmd_ha_ch_grp_set_chassis_prio, NULL, > > "", RW }, > > > > + /* Static_MAC_Binding commands */ > > + { "static-mac-binding-add", 3, 3, "LOGICAL_PORT IP MAC", > > + nbctl_pre_static_mac_binding_add, nbctl_static_mac_binding_add, NULL, > > + "--may-exist", RW }, > > + { "static-mac-binding-del", 2, 2, "LOGICAL_PORT IP", > > + nbctl_pre_static_mac_binding_del, nbctl_static_mac_binding_del, NULL, > > + "--if-exists", RW }, > > + { "static-mac-binding-list", 0, 1, "[LOGICAL_PORT]", > > + nbctl_pre_static_mac_binding_list, nbctl_static_mac_binding_list, > > NULL, > > + "", RO }, > > + > > {NULL, 0, 0, NULL, NULL, NULL, NULL, "", RO}, > > }; > > > > -- > > 2.22.3 > > > > _______________________________________________ > > 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 > _______________________________________________ dev mailing list [email protected] https://mail.openvswitch.org/mailman/listinfo/ovs-dev
