> This commit introduces a new `ct_lb_mark_local` action that filters backends > based on local chassis bindings for load balancing. By forming OpenFlow groups > for balancing only with local backends. > In the future, this will be used to implement distributed balancers. > > Suggested-by: Vladislav Odintsov <[email protected]> > Signed-off-by: Alexandra Rukomoinikova <[email protected]>
Acked-by: Lorenzo Bianconi <[email protected]> > --- > controller/lflow.c | 17 ++++ > controller/lflow.h | 1 + > controller/ovn-controller.c | 1 + > include/ovn/actions.h | 11 +++ > lib/actions.c | 149 ++++++++++++++++++++++++++++++------ > lib/ovn-util.c | 2 +- > tests/ovn.at | 11 +++ > tests/test-ovn.c | 11 +++ > utilities/ovn-trace.c | 2 + > 9 files changed, 179 insertions(+), 26 deletions(-) > --- > v1 --> v2: added parsing tests for new action > --- > diff --git a/controller/lflow.c b/controller/lflow.c > index e84fb2486..9979508eb 100644 > --- a/controller/lflow.c > +++ b/controller/lflow.c > @@ -64,6 +64,7 @@ struct lookup_port_aux { > const struct sbrec_logical_flow *lflow; > struct objdep_mgr *deps_mgr; > const struct hmap *chassis_tunnels; > + const struct shash *local_bindings; > }; > > struct condition_aux { > @@ -153,6 +154,20 @@ lookup_port_cb(const void *aux_, const char *port_name, > unsigned int *portp) > return false; > } > > +/* Given the OVN port name, get true if port locates on local chassis, > + * false otherwise. */ > +static bool > +lookup_local_port_cb(const void *aux_, const char *port_name) > +{ > + const struct lookup_port_aux *aux = aux_; > + > + if (local_binding_get_primary_pb(aux->local_bindings, port_name)) { > + return true; > + } > + > + return false; > +} > + > /* Given the OVN port name, get its openflow port */ > static bool > tunnel_ofport_cb(const void *aux_, const char *port_name, ofp_port_t *ofport) > @@ -857,6 +872,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow > *lflow, > .lflow = lflow, > .deps_mgr = l_ctx_out->lflow_deps_mgr, > .chassis_tunnels = l_ctx_in->chassis_tunnels, > + .local_bindings = l_ctx_in->lbinding_lports, > }; > > /* Parse any meter to be used if this flow should punt packets to > @@ -871,6 +887,7 @@ add_matches_to_flow_table(const struct sbrec_logical_flow > *lflow, > struct ofpbuf ofpacts = OFPBUF_STUB_INITIALIZER(ofpacts_stub); > struct ovnact_encode_params ep = { > .lookup_port = lookup_port_cb, > + .lookup_local_port = lookup_local_port_cb, > .tunnel_ofport = tunnel_ofport_cb, > .aux = &aux, > .is_switch = ldp->is_switch, > diff --git a/controller/lflow.h b/controller/lflow.h > index d82acc0d8..0cde1ebf4 100644 > --- a/controller/lflow.h > +++ b/controller/lflow.h > @@ -138,6 +138,7 @@ struct lflow_ctx_in { > const struct smap *template_vars; > const struct flow_collector_ids *collector_ids; > const struct hmap *local_lbs; > + const struct shash *lbinding_lports; > bool localnet_learn_fdb; > bool localnet_learn_fdb_changed; > bool explicit_arp_ns_output; > diff --git a/controller/ovn-controller.c b/controller/ovn-controller.c > index c2dab41c1..74e900fc2 100644 > --- a/controller/ovn-controller.c > +++ b/controller/ovn-controller.c > @@ -3933,6 +3933,7 @@ init_lflow_ctx(struct engine_node *node, > l_ctx_in->template_vars = &template_vars->local_templates; > l_ctx_in->collector_ids = &fo->collector_ids; > l_ctx_in->local_lbs = &lb_data->local_lbs; > + l_ctx_in->lbinding_lports = &rt_data->lbinding_data.bindings; > > l_ctx_out->flow_table = &fo->flow_table; > l_ctx_out->group_table = &fo->group_table; > diff --git a/include/ovn/actions.h b/include/ovn/actions.h > index d3f0bfd04..2ca8dac8f 100644 > --- a/include/ovn/actions.h > +++ b/include/ovn/actions.h > @@ -75,6 +75,7 @@ struct collector_set_ids; > OVNACT(CT_SNAT_IN_CZONE, ovnact_ct_nat) \ > OVNACT(CT_LB, ovnact_ct_lb) \ > OVNACT(CT_LB_MARK, ovnact_ct_lb) \ > + OVNACT(CT_LB_MARK_LOCAL, ovnact_ct_lb) \ > OVNACT(SELECT, ovnact_select) \ > OVNACT(CT_CLEAR, ovnact_null) \ > OVNACT(CT_COMMIT_NAT, ovnact_ct_commit_to_zone) \ > @@ -311,6 +312,12 @@ struct ovnact_ct_commit_to_zone { > uint8_t ltable; > }; > > +enum ovnact_ct_lb_type { > + OVNACT_CT_LB_TYPE_LABEL, > + OVNACT_CT_LB_TYPE_MARK, > + OVNACT_CT_LB_LOCAL_TYPE_MARK, > +}; > + > enum ovnact_ct_lb_flag { > OVNACT_CT_LB_FLAG_NONE, > OVNACT_CT_LB_FLAG_SKIP_SNAT, > @@ -324,6 +331,7 @@ struct ovnact_ct_lb_dst { > ovs_be32 ipv4; > }; > uint16_t port; > + char *port_name; > }; > > /* OVNACT_CT_LB/OVNACT_CT_LB_MARK. */ > @@ -891,6 +899,9 @@ struct ovnact_encode_params { > bool (*lookup_port)(const void *aux, const char *port_name, > unsigned int *portp); > > + /* Check if the logical port is bound to this chassis. */ > + bool (*lookup_local_port)(const void *aux, const char *port_name); > + > /* Looks up tunnel port to a chassis by its port name. If found, stores > * its openflow port number in '*ofport' and returns true; > * otherwise, returns false. */ > diff --git a/lib/actions.c b/lib/actions.c > index 53f4d20a9..ee508fd85 100644 > --- a/lib/actions.c > +++ b/lib/actions.c > @@ -1187,8 +1187,25 @@ ovnact_ct_commit_to_zone_free(struct > ovnact_ct_commit_to_zone *cn OVS_UNUSED) > { > } > > + > +static bool > +parse_ct_lb_logical_port_name(struct action_context *ctx, > + struct ovnact_ct_lb_dst *dst) > +{ > + if (ctx->lexer->token.type != LEX_T_STRING) { > + return false; > + } > + > + dst->port_name = xstrdup(ctx->lexer->token.s); > + > + lexer_get(ctx->lexer); > + > + return true; > +} > + > static void > -parse_ct_lb_action(struct action_context *ctx, bool ct_lb_mark) > +parse_ct_lb_action(struct action_context *ctx, > + enum ovnact_ct_lb_type type) > { > if (ctx->pp->cur_ltable >= ctx->pp->n_tables) { > lexer_error(ctx->lexer, "\"ct_lb\" action not allowed in last > table."); > @@ -1211,7 +1228,19 @@ parse_ct_lb_action(struct action_context *ctx, bool > ct_lb_mark) > > while (!lexer_match(ctx->lexer, LEX_T_SEMICOLON) && > !lexer_match(ctx->lexer, LEX_T_RPAREN)) { > - struct ovnact_ct_lb_dst dst; > + struct ovnact_ct_lb_dst dst = {0}; > + > + if (type == OVNACT_CT_LB_LOCAL_TYPE_MARK) { > + if (!parse_ct_lb_logical_port_name(ctx, &dst)) { > + vector_destroy(&dsts); > + lexer_syntax_error(ctx->lexer, > + "expecting logical port name " > + "for distributed load balancer"); > + return; > + } > + lexer_get(ctx->lexer); > + } > + > if (lexer_match(ctx->lexer, LEX_T_LSQUARE)) { > /* IPv6 address and port */ > if (ctx->lexer->token.type != LEX_T_INTEGER > @@ -1298,8 +1327,19 @@ parse_ct_lb_action(struct action_context *ctx, bool > ct_lb_mark) > } > } > > - struct ovnact_ct_lb *cl = ct_lb_mark ? > ovnact_put_CT_LB_MARK(ctx->ovnacts) > - : ovnact_put_CT_LB(ctx->ovnacts); > + struct ovnact_ct_lb *cl; > + switch (type) { > + case OVNACT_CT_LB_TYPE_LABEL: > + cl = ovnact_put_CT_LB(ctx->ovnacts); > + break; > + case OVNACT_CT_LB_TYPE_MARK: > + cl = ovnact_put_CT_LB_MARK(ctx->ovnacts); > + break; > + case OVNACT_CT_LB_LOCAL_TYPE_MARK: > + cl = ovnact_put_CT_LB_MARK_LOCAL(ctx->ovnacts); > + break; > + } > + > cl->ltable = ctx->pp->cur_ltable + 1; > cl->n_dsts = vector_len(&dsts); > cl->dsts = vector_steal_array(&dsts); > @@ -1308,21 +1348,26 @@ parse_ct_lb_action(struct action_context *ctx, bool > ct_lb_mark) > } > > static void > -format_ct_lb(const struct ovnact_ct_lb *cl, struct ds *s, bool ct_lb_mark) > +format_ct_lb(const struct ovnact_ct_lb *cl, struct ds *s, > + enum ovnact_ct_lb_type type) > { > - if (ct_lb_mark) { > - ds_put_cstr(s, "ct_lb_mark"); > - } else { > - ds_put_cstr(s, "ct_lb"); > - } > + static const char *const lb_action_strings[] = { > + [OVNACT_CT_LB_TYPE_LABEL] = "ct_lb", > + [OVNACT_CT_LB_TYPE_MARK] = "ct_lb_mark", > + [OVNACT_CT_LB_LOCAL_TYPE_MARK] = "ct_lb_mark_local", > + }; > + ds_put_cstr(s, lb_action_strings[type]); > + > if (cl->n_dsts) { > ds_put_cstr(s, "(backends="); > for (size_t i = 0; i < cl->n_dsts; i++) { > if (i) { > ds_put_char(s, ','); > } > - > const struct ovnact_ct_lb_dst *dst = &cl->dsts[i]; > + if (type == OVNACT_CT_LB_LOCAL_TYPE_MARK) { > + ds_put_format(s, "\"%s\":", dst->port_name); > + } > if (dst->family == AF_INET) { > ds_put_format(s, IP_FMT, IP_ARGS(dst->ipv4)); > if (dst->port) { > @@ -1363,20 +1408,36 @@ format_ct_lb(const struct ovnact_ct_lb *cl, struct ds > *s, bool ct_lb_mark) > static void > format_CT_LB(const struct ovnact_ct_lb *cl, struct ds *s) > { > - format_ct_lb(cl, s, false); > + format_ct_lb(cl, s, OVNACT_CT_LB_TYPE_LABEL); > } > > static void > format_CT_LB_MARK(const struct ovnact_ct_lb *cl, struct ds *s) > { > - format_ct_lb(cl, s, true); > + format_ct_lb(cl, s, OVNACT_CT_LB_TYPE_MARK); > +} > + > +static void > +format_CT_LB_MARK_LOCAL(const struct ovnact_ct_lb *cl, struct ds *s) > +{ > + format_ct_lb(cl, s, OVNACT_CT_LB_LOCAL_TYPE_MARK); > +} > + > +static inline void > +append_nat_destination(struct ds *ds, const char *ip_addr, > + bool needs_brackets) > +{ > + ds_put_format(ds, "ct(nat(dst=%s%s%s", > + needs_brackets ? "[" : "", > + ip_addr, > + needs_brackets ? "]" : ""); > } > > static void > encode_ct_lb(const struct ovnact_ct_lb *cl, > const struct ovnact_encode_params *ep, > struct ofpbuf *ofpacts, > - bool ct_lb_mark) > + enum ovnact_ct_lb_type type) > { > uint8_t recirc_table = cl->ltable + first_ptable(ep, ep->pipeline); > if (!cl->n_dsts) { > @@ -1408,7 +1469,8 @@ encode_ct_lb(const struct ovnact_ct_lb *cl, > struct ofpact_group *og; > uint32_t zone_reg = ep->is_switch ? MFF_LOG_CT_ZONE - MFF_REG0 > : MFF_LOG_DNAT_ZONE - MFF_REG0; > - const char *flag_reg = ct_lb_mark ? "ct_mark" : "ct_label"; > + const char *flag_reg = (type == OVNACT_CT_LB_TYPE_LABEL) > + ? "ct_label" : "ct_mark"; > > const char *ct_flag_value; > switch (cl->ct_flag) { > @@ -1435,32 +1497,50 @@ encode_ct_lb(const struct ovnact_ct_lb *cl, > BUILD_ASSERT(MFF_LOG_CT_ZONE < MFF_REG0 + FLOW_N_REGS); > BUILD_ASSERT(MFF_LOG_DNAT_ZONE >= MFF_REG0); > BUILD_ASSERT(MFF_LOG_DNAT_ZONE < MFF_REG0 + FLOW_N_REGS); > + > + size_t n_active_backends = 0; > for (size_t bucket_id = 0; bucket_id < cl->n_dsts; bucket_id++) { > const struct ovnact_ct_lb_dst *dst = &cl->dsts[bucket_id]; > char ip_addr[INET6_ADDRSTRLEN]; > + > if (dst->family == AF_INET) { > inet_ntop(AF_INET, &dst->ipv4, ip_addr, sizeof ip_addr); > } else { > inet_ntop(AF_INET6, &dst->ipv6, ip_addr, sizeof ip_addr); > } > - ds_put_format(&ds, > ",bucket=bucket_id=%"PRIuSIZE",weight:100,actions=" > - "ct(nat(dst=%s%s%s", bucket_id, > - dst->family == AF_INET6 && dst->port ? "[" : "", > - ip_addr, > - dst->family == AF_INET6 && dst->port ? "]" : ""); > + > + if (type == OVNACT_CT_LB_LOCAL_TYPE_MARK > + && !ep->lookup_local_port(ep->aux, dst->port_name)) { > + continue; > + } > + > + ds_put_format(&ds, > ",bucket=bucket_id=%"PRIuSIZE",weight:100,actions=", > + bucket_id); > + > + bool needs_brackets = (dst->family == AF_INET6 && dst->port); > + append_nat_destination(&ds, ip_addr, needs_brackets); > + > if (dst->port) { > ds_put_format(&ds, ":%"PRIu16, dst->port); > } > + > ds_put_format(&ds, "),commit,table=%d,zone=NXM_NX_REG%d[0..15]," > "exec(set_field:" > OVN_CT_MASKED_STR(OVN_CT_NATTED) > "->%s", > recirc_table, zone_reg, flag_reg); > + > if (ct_flag_value) { > ds_put_format(&ds, ",set_field:%s->%s", ct_flag_value, flag_reg); > } > > ds_put_cstr(&ds, "))"); > + > + n_active_backends++; > + } > + > + if (!n_active_backends) { > + return; > } > > table_id = ovn_extend_table_assign_id(ep->group_table, ds_cstr(&ds), > @@ -1480,7 +1560,7 @@ encode_CT_LB(const struct ovnact_ct_lb *cl, > const struct ovnact_encode_params *ep, > struct ofpbuf *ofpacts) > { > - encode_ct_lb(cl, ep, ofpacts, false); > + encode_ct_lb(cl, ep, ofpacts, OVNACT_CT_LB_TYPE_LABEL); > } > > static void > @@ -1488,13 +1568,30 @@ encode_CT_LB_MARK(const struct ovnact_ct_lb *cl, > const struct ovnact_encode_params *ep, > struct ofpbuf *ofpacts) > { > - encode_ct_lb(cl, ep, ofpacts, true); > + encode_ct_lb(cl, ep, ofpacts, OVNACT_CT_LB_TYPE_MARK); > } > > static void > -ovnact_ct_lb_free(struct ovnact_ct_lb *ct_lb) > +encode_CT_LB_MARK_LOCAL(const struct ovnact_ct_lb *cl, > + const struct ovnact_encode_params *ep, > + struct ofpbuf *ofpacts) > +{ > + encode_ct_lb(cl, ep, ofpacts, OVNACT_CT_LB_LOCAL_TYPE_MARK); > +} > + > +static void > +ovnact_ct_lb_free_dsts(struct ovnact_ct_lb *ct_lb) > { > + for (size_t i = 0; i < ct_lb->n_dsts; i++) { > + free(ct_lb->dsts[i].port_name); > + } > free(ct_lb->dsts); > +} > + > +static void > +ovnact_ct_lb_free(struct ovnact_ct_lb *ct_lb) > +{ > + ovnact_ct_lb_free_dsts(ct_lb); > free(ct_lb->hash_fields); > } > > @@ -5904,9 +6001,11 @@ parse_action(struct action_context *ctx) > } else if (lexer_match_id(ctx->lexer, "ct_lb")) { > VLOG_WARN_RL(&rl, "The \"ct_lb\" action is deprecated please " > "consider using a different action."); > - parse_ct_lb_action(ctx, false); > + parse_ct_lb_action(ctx, OVNACT_CT_LB_TYPE_LABEL); > } else if (lexer_match_id(ctx->lexer, "ct_lb_mark")) { > - parse_ct_lb_action(ctx, true); > + parse_ct_lb_action(ctx, OVNACT_CT_LB_TYPE_MARK); > + } else if (lexer_match_id(ctx->lexer, "ct_lb_mark_local")) { > + parse_ct_lb_action(ctx, OVNACT_CT_LB_LOCAL_TYPE_MARK); > } else if (lexer_match_id(ctx->lexer, "ct_clear")) { > ovnact_put_CT_CLEAR(ctx->ovnacts); > } else if (lexer_match_id(ctx->lexer, "ct_commit_nat")) { > diff --git a/lib/ovn-util.c b/lib/ovn-util.c > index d27983d1e..e020cb81d 100644 > --- a/lib/ovn-util.c > +++ b/lib/ovn-util.c > @@ -921,7 +921,7 @@ ip_address_and_port_from_lb_key(const char *key, char > **ip_address, > * > * NOTE: If OVN_NORTHD_PIPELINE_CSUM is updated make sure to double check > * whether an update of OVN_INTERNAL_MINOR_VER is required. */ > -#define OVN_NORTHD_PIPELINE_CSUM "2164662054 10958" > +#define OVN_NORTHD_PIPELINE_CSUM "4239189964 11014" > #define OVN_INTERNAL_MINOR_VER 11 > > /* Returns the OVN version. The caller must free the returned value. */ > diff --git a/tests/ovn.at b/tests/ovn.at > index 0a3671368..e163c14e3 100644 > --- a/tests/ovn.at > +++ b/tests/ovn.at > @@ -2375,6 +2375,17 @@ mirror("lsp1"); > mirror(lsp1); > Syntax error at `lsp1' expecting port name string. > > +ct_lb_mark_local(backends="lsp1":192.168.0.101:10880); > + encodes as group:25 > + uses group: id(25), > name(type=select,selection_method=dp_hash,bucket=bucket_id=0,weight:100,actions=ct(nat(dst=192.168.0.101:10880),commit,table=oflow_in_table,zone=NXM_NX_REG13[[0..15]],exec(set_field:2/2->ct_mark))) > + has prereqs ip > + > +ct_lb_mark_local(backends=192.168.0.101:80); > + Syntax error at `192.168.0.101' expecting logical port name for > distributed load balancer. > + > +ct_lb_mark_local(backends=lsp1:192.168.0.101:10880); > + Syntax error at `lsp1' expecting logical port name for distributed load > balancer. > + > # Miscellaneous negative tests. > ; > Syntax error at `;'. > diff --git a/tests/test-ovn.c b/tests/test-ovn.c > index fae7e7bd5..1132714f6 100644 > --- a/tests/test-ovn.c > +++ b/tests/test-ovn.c > @@ -265,6 +265,16 @@ lookup_port_cb(const void *ports_, const char > *port_name, unsigned int *portp) > return true; > } > > +static bool > +lookup_local_port_cb(const void *ports_, const char *port_name) > +{ > + const struct simap *ports = ports_; > + const struct simap_node *node = simap_find(ports, port_name); > + > + > + return node ? true : false; > +} > + > static bool > lookup_tunnel_ofport(const void *ports_, const char *port_name, > ofp_port_t *ofport) > @@ -1361,6 +1371,7 @@ test_parse_actions(struct ovs_cmdl_context *ctx > OVS_UNUSED) > /* Encode the actions into OpenFlow and print. */ > const struct ovnact_encode_params ep = { > .lookup_port = lookup_port_cb, > + .lookup_local_port = lookup_local_port_cb, > .tunnel_ofport = lookup_tunnel_ofport, > .aux = &ports, > .is_switch = true, > diff --git a/utilities/ovn-trace.c b/utilities/ovn-trace.c > index 9d9f915da..f288c8a8f 100644 > --- a/utilities/ovn-trace.c > +++ b/utilities/ovn-trace.c > @@ -3590,6 +3590,8 @@ trace_actions(const struct ovnact *ovnacts, size_t > ovnacts_len, > case OVNACT_CT_STATE_SAVE: > execute_ct_save_state(ovnact_get_CT_STATE_SAVE(a), uflow, super); > break; > + case OVNACT_CT_LB_MARK_LOCAL: > + break; > } > } > ofpbuf_uninit(&stack); > -- > 2.48.1 > > _______________________________________________ > 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
