@@ -72,7 +72,8 @@ struct simap;
OVNACT(PUT_DHCPV6_OPTS, ovnact_put_dhcp_opts) \
OVNACT(SET_QUEUE, ovnact_set_queue) \
OVNACT(DNS_LOOKUP, ovnact_dns_lookup) \
- OVNACT(LOG, ovnact_log)
+ OVNACT(LOG, ovnact_log) \
+ OVNACT(MULTIPATH, ovnact_multipath)
/* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
enum OVS_PACKED_ENUM ovnact_type {
@@ -274,6 +275,35 @@ struct ovnact_log {
char *name;
};
+/* Fields to use when hashing flows. */
+enum ovnact_hash_fields {
+ OVNACT_HASH_FIELDS_ETH_SRC,
+ OVNACT_HASH_FIELDS_SYMMETRIC_L4,
+ OVNACT_HASH_FIELDS_SYMMETRIC_L3L4,
+ OVNACT_HASH_FIELDS_SYMMETRIC_L3L4_UDP,
+ OVNACT_HASH_FIELDS_NW_SRC,
+ OVNACT_HASH_FIELDS_NW_DST
+};
+
+/* Multipath link choice algorithm to apply. */
+enum ovnact_mp_algorithm {
+ OVNACT_MP_ALG_MODULO_N,
+ OVNACT_MP_ALG_HASH_THRESHOLD,
+ OVNACT_MP_ALG_HRW,
+ OVNACT_MP_ALG_ITER_HASH
+};
+
+/* OVNACT_MULTIPATH. */
+struct ovnact_multipath {
+ struct ovnact ovnact;
+ enum ovnact_hash_fields fields;
+ uint16_t basis;
+ enum ovnact_mp_algorithm algorithm;
+ uint16_t n_links;
+ uint32_t arg;
+ struct expr_field dst;
+};
+
/* Internal use by the helpers below. */
void ovnact_init(struct ovnact *, enum ovnact_type, size_t len);
void *ovnact_put(struct ofpbuf *, enum ovnact_type, size_t len);
@@ -1873,6 +1873,172 @@ ovnact_log_free(struct ovnact_log *log)
free(log->name);
}
+static void
+parse_multipath(struct action_context *ctx)
+{
+ int basis;
+ int n_links;
+ int arg;
+ struct ovnact_multipath *put_multipath =
+ ovnact_put_MULTIPATH(ctx->ovnacts);
+
+ if (!lexer_force_match(ctx->lexer, LEX_T_LPAREN)) {
+ lexer_error(ctx->lexer, " expecting parenthesis \"(\" ");
+ return;
+ }
+
+ if (lexer_match_id(ctx->lexer, "eth_src")) {
+ put_multipath->fields = OVNACT_HASH_FIELDS_ETH_SRC;
+ } else if (lexer_match_id(ctx->lexer, "symmetric_l4")) {
+ put_multipath->fields = OVNACT_HASH_FIELDS_SYMMETRIC_L4;
+ } else if (lexer_match_id(ctx->lexer, "symmetric_l3l4")) {
+ put_multipath->fields = OVNACT_HASH_FIELDS_SYMMETRIC_L3L4;
+ } else if (lexer_match_id(ctx->lexer, "symmetric_l3l4+udp")) {
+ put_multipath->fields = OVNACT_HASH_FIELDS_SYMMETRIC_L3L4_UDP;
+ } else if (lexer_match_id(ctx->lexer, "nw_src")) {
+ put_multipath->fields = OVNACT_HASH_FIELDS_NW_SRC;
+ } else if (lexer_match_id(ctx->lexer, "nw_dst")) {
+ put_multipath->fields = OVNACT_HASH_FIELDS_NW_DST;
+ } else {
+ lexer_error(ctx->lexer, "multipath gets invalid hash fields type");
+ return;
+ }
+
+ lexer_match(ctx->lexer, LEX_T_COMMA);
+
+ if (!lexer_get_int(ctx->lexer, &basis)) {
+ lexer_error(ctx->lexer, "multipath requires numeric value for basis");
+ return;
+ }
+ if (basis < 0 || basis >= 65535) {
+ lexer_error(ctx->lexer, "multipath basis is not in valid range");
+ return;
+ }
+
+ put_multipath->basis = basis;
+ lexer_match(ctx->lexer, LEX_T_COMMA);
+
+ if (lexer_match_id(ctx->lexer, "modulo_n")) {
+ put_multipath->algorithm = OVNACT_MP_ALG_MODULO_N;
+ } else if (lexer_match_id(ctx->lexer, "hash_threshold")) {
+ put_multipath->algorithm = OVNACT_MP_ALG_HASH_THRESHOLD;
+ } else if (lexer_match_id(ctx->lexer, "hrw")) {
+ put_multipath->algorithm = OVNACT_MP_ALG_HRW;
+ } else if (lexer_match_id(ctx->lexer, "iter_hash")) {
+ put_multipath->algorithm = OVNACT_MP_ALG_ITER_HASH;
+ } else {
+ lexer_error(ctx->lexer, "multipath gets invalid algorithm type");
+ return;
+ }
+ lexer_match(ctx->lexer, LEX_T_COMMA);
+
+ if (!lexer_get_int(ctx->lexer, &n_links)) {
+ lexer_error(ctx->lexer,
+ "multipath requires numeric value for n_links");
+ return;
+ }
+ if (n_links < 0 || n_links >= 65535) {
+ lexer_error(ctx->lexer, "multipath n_links is not in valid range");
+ return;
+ }
+ put_multipath->n_links = n_links;
+ lexer_match(ctx->lexer, LEX_T_COMMA);
+
+ if (!lexer_get_int(ctx->lexer, &arg)) {
+ lexer_error(ctx->lexer, "multipath requires numeric value for args");
+ return;
+ }
+ if (arg < 0) {
+ lexer_error(ctx->lexer, "multipath arg is not in valid range");
+ return;
+ }
+ put_multipath->arg = arg;
+ lexer_match(ctx->lexer, LEX_T_COMMA);
+
+ if (!expr_field_parse(ctx->lexer, ctx->pp->symtab,
+ &put_multipath->dst, &ctx->prereqs)) {
+ lexer_error(ctx->lexer, "multipath gets wrong dst register");
+ return;
+ }
+
+ lexer_force_match(ctx->lexer, LEX_T_RPAREN);
+}
+
+static void
+format_MULTIPATH(const struct ovnact_multipath *multipath,
+ struct ds *s)
+{
+ const char *fields, *algorithm;
+
+ switch (multipath->fields) {
+ case OVNACT_HASH_FIELDS_ETH_SRC:
+ fields = "eth_src";
+ break;
+ case OVNACT_HASH_FIELDS_SYMMETRIC_L4:
+ fields = "symmetric_l4";
+ break;
+ case OVNACT_HASH_FIELDS_SYMMETRIC_L3L4:
+ fields = "symmetric_l3l4";
+ break;
+ case OVNACT_HASH_FIELDS_SYMMETRIC_L3L4_UDP:
+ fields = "symmetric_l3l4+udp";
+ break;
+ case OVNACT_HASH_FIELDS_NW_SRC:
+ fields = "nw_src";
+ break;
+ case OVNACT_HASH_FIELDS_NW_DST:
+ fields = "nw_dst";
+ break;
+ default:
+ fields = "<unknown>";
+ }
+
+ switch (multipath->algorithm) {
+ case OVNACT_MP_ALG_MODULO_N:
+ algorithm = "modulo_n";
+ break;
+ case OVNACT_MP_ALG_HASH_THRESHOLD:
+ algorithm = "hash_threshold";
+ break;
+ case OVNACT_MP_ALG_HRW:
+ algorithm = "hrw";
+ break;
+ case OVNACT_MP_ALG_ITER_HASH:
+ algorithm = "iter_hash";
+ break;
+ default:
+ algorithm = "<unknown>";
+ }
+
+ ds_put_format(s, "multipath(%s,%u,%s,%u,%u,",
+ fields, multipath->basis,
+ algorithm, multipath->n_links,
+ multipath->arg);
+ expr_field_format(&multipath->dst, s);
+ ds_put_format(s, ");");
+}
+
+static void
+encode_MULTIPATH(const struct ovnact_multipath *ovnact_mp,
+ const struct ovnact_encode_params *ep OVS_UNUSED,
+ struct ofpbuf *ofpacts)
+{
+ struct ofpact_multipath *ofpact_mp = ofpact_put_MULTIPATH(ofpacts);
+
+ ofpact_init_MULTIPATH(ofpact_mp);
+ ofpact_mp->fields = ovnact_mp->fields;
+ ofpact_mp->basis = ovnact_mp->basis;
+ ofpact_mp->algorithm = ovnact_mp->algorithm;
+ ofpact_mp->max_link = ovnact_mp->n_links - 1;
+ ofpact_mp->arg = ovnact_mp->arg;
+ ofpact_mp->dst = expr_resolve_field(&ovnact_mp->dst);
+}
+
+static void
+ovnact_multipath_free(struct ovnact_multipath *mp OVS_UNUSED)
+{
+}
+
/* Parses an assignment or exchange or put_dhcp_opts action. */
static void
parse_set_action(struct action_context *ctx)
@@ -1954,6 +2120,8 @@ parse_action(struct action_context *ctx)
parse_SET_QUEUE(ctx);
} else if (lexer_match_id(ctx->lexer, "log")) {
parse_LOG(ctx);
+ } else if (lexer_match_id(ctx->lexer, "multipath")) {
+ parse_multipath(ctx);
} else {
lexer_syntax_error(ctx->lexer, "expecting action");
}
@@ -25,6 +25,7 @@
#include "fatal-signal.h"
#include "flow.h"
#include "nx-match.h"
+#include "multipath.h"
#include "openvswitch/dynamic-string.h"
#include "openvswitch/json.h"
#include "openvswitch/ofp-actions.h"
@@ -1695,6 +1696,36 @@ execute_log(const struct ovnact_log *log, struct flow *uflow,
}
static void
+execute_multipath(const struct ovnact_multipath *ovnact_mp,
+ struct flow *uflow,
+ struct ovs_list *super)
+{
+ struct ofpact_multipath ofpact_mp;
+ struct flow_wildcards wc;
+ union mf_subvalue cst;
+ struct ds s = DS_EMPTY_INITIALIZER;
+
+ ofpact_init_MULTIPATH(&ofpact_mp);
+ ofpact_mp.fields = ovnact_mp->fields;
+ ofpact_mp.basis = ovnact_mp->basis;
+ ofpact_mp.algorithm = ovnact_mp->algorithm;
+ ofpact_mp.max_link = ovnact_mp->n_links - 1;
+ ofpact_mp.arg = ovnact_mp->arg;
+ ofpact_mp.dst = expr_resolve_field(&ovnact_mp->dst);
+
+ multipath_execute(&ofpact_mp, uflow, &wc);
+
+ expr_field_format(&ovnact_mp->dst, &s);
+ ds_put_cstr(&s, " = ");
+ mf_read_subfield(&ofpact_mp.dst, uflow, &cst);
+ ds_put_hex(&s, &cst, sizeof cst);
+ ds_put_cstr(&s, "(multipath hash result)");
+
+ ovntrace_node_append(super, OVNTRACE_NODE_TRANSFORMATION,
+ "%s", ds_cstr(&s));
+}
+
+static void
trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
const struct ovntrace_datapath *dp, struct flow *uflow,
uint8_t table_id, enum ovnact_pipeline pipeline,
@@ -1833,6 +1864,9 @@ trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
case OVNACT_LOG:
execute_log(ovnact_get_LOG(a), uflow, super);
break;
+ case OVNACT_MULTIPATH:
+ execute_multipath(ovnact_get_MULTIPATH(a), uflow, super);
+ break;
}
}
1. Update actions.h, actions.c to handle multipath action in ovn-controller. 2. Update ovn-trace to simulate action of multipath. It helps multipath debugging. Signed-off-by: Zhenyu Gao <sysugaozhenyu@gmail.com> --- include/ovn/actions.h | 32 ++++++++- ovn/lib/actions.c | 168 ++++++++++++++++++++++++++++++++++++++++++++++ ovn/utilities/ovn-trace.c | 34 ++++++++++ 3 files changed, 233 insertions(+), 1 deletion(-)