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]> --- 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
