[ovs-dev,v2,2/3] Add multipath support in ovn-controller and ovn-trace

Message ID 20170926095300.28876-1-sysugaozhenyu@gmail.com
State New
Headers show
Series
  • [ovs-dev,v2,1/3] Add multipath static router in OVN northd and north-db
Related show

Commit Message

Gao Zhenyu Sept. 26, 2017, 9:53 a.m.
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(-)

Patch

diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index 0a04af7..574cc9d 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -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);
diff --git a/ovn/lib/actions.c b/ovn/lib/actions.c
index d0d73b6..8b41af2 100644
--- a/ovn/lib/actions.c
+++ b/ovn/lib/actions.c
@@ -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");
     }
diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c
index 59083ee..af0c7da 100644
--- a/ovn/utilities/ovn-trace.c
+++ b/ovn/utilities/ovn-trace.c
@@ -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;
         }
 
     }