[ovs-dev,v2,5/6] ovn: Support OVS action 'check_pkt_larger' in OVN

Message ID 20190412130554.28643-1-nusiddiq@redhat.com
State Superseded
Headers show
Series
  • Address MTU issue for larger packets in OVN
Related show

Commit Message

Numan Siddique April 12, 2019, 1:05 p.m.
From: Numan Siddique <nusiddiq@redhat.com>

Previous commit added a new OVS action 'check_pkt_larger'. This
patch supports that action in OVN. The syntax to use this would be

reg0[0] = check_pkt_larger(LEN)

Upcoming commit will make use of this action in ovn-northd and
will generate an ICMPv4 packet if the packet length is greater than
the specified length.

Signed-off-by: Numan Siddique <nusiddiq@redhat.com>
Acked-by: Mark Michelson <mmichels@redhat.com>
---
 include/ovn/actions.h     | 10 +++++++-
 ovn/lib/actions.c         | 53 +++++++++++++++++++++++++++++++++++++++
 ovn/ovn-sb.xml            | 21 ++++++++++++++++
 ovn/utilities/ovn-trace.c |  4 ++-
 tests/ovn.at              | 10 ++++++++
 5 files changed, 96 insertions(+), 2 deletions(-)

Patch

diff --git a/include/ovn/actions.h b/include/ovn/actions.h
index af8b0a4a0..e07ad9aa3 100644
--- a/include/ovn/actions.h
+++ b/include/ovn/actions.h
@@ -82,7 +82,8 @@  struct ovn_extend_table;
     OVNACT(PUT_ND_RA_OPTS,    ovnact_put_opts)        \
     OVNACT(ND_NS,             ovnact_nest)            \
     OVNACT(SET_METER,         ovnact_set_meter)       \
-    OVNACT(OVNFIELD_LOAD,     ovnact_load)
+    OVNACT(OVNFIELD_LOAD,     ovnact_load)            \
+    OVNACT(CHECK_PKT_LARGER,  ovnact_check_pkt_larger)
 
 /* enum ovnact_type, with a member OVNACT_<ENUM> for each action. */
 enum OVS_PACKED_ENUM ovnact_type {
@@ -310,6 +311,13 @@  struct ovnact_set_meter {
     uint64_t burst;                  /* burst rate field, in kbps. */
 };
 
+/* OVNACT_CHECK_IP_PKT_LARGER. */
+struct ovnact_check_pkt_larger {
+    struct ovnact ovnact;
+    uint16_t pkt_len;
+    struct expr_field dst;      /* 1-bit destination field. */
+};
+
 /* 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 f78e6ffcb..a37e115e5 100644
--- a/ovn/lib/actions.c
+++ b/ovn/lib/actions.c
@@ -2359,6 +2359,55 @@  encode_OVNFIELD_LOAD(const struct ovnact_load *load,
     }
 }
 
+static void
+parse_check_pkt_larger(struct action_context *ctx,
+                       const struct expr_field *dst,
+                       struct ovnact_check_pkt_larger *cipl)
+{
+    int pkt_len;
+
+    lexer_get(ctx->lexer); /* Skip check_pkt_len. */
+    if (!lexer_force_match(ctx->lexer, LEX_T_LPAREN)
+        || !lexer_get_int(ctx->lexer, &pkt_len)
+        || !lexer_force_match(ctx->lexer, LEX_T_RPAREN)) {
+        return;
+    }
+
+    /* Validate that the destination is a 1-bit, modifiable field. */
+    char *error = expr_type_check(dst, 1, true);
+    if (error) {
+        lexer_error(ctx->lexer, "%s", error);
+        free(error);
+        return;
+    }
+    cipl->dst = *dst;
+    cipl->pkt_len = pkt_len;
+}
+
+static void
+format_CHECK_PKT_LARGER(const struct ovnact_check_pkt_larger *cipl,
+                        struct ds *s)
+{
+    expr_field_format(&cipl->dst, s);
+    ds_put_format(s, " = check_pkt_larger(%d);", cipl->pkt_len);
+}
+
+static void
+encode_CHECK_PKT_LARGER(const struct ovnact_check_pkt_larger *cipl,
+                        const struct ovnact_encode_params *ep OVS_UNUSED,
+                        struct ofpbuf *ofpacts)
+{
+    struct ofpact_check_pkt_larger *check_pkt_larger =
+        ofpact_put_CHECK_PKT_LARGER(ofpacts);
+    check_pkt_larger->pkt_len = cipl->pkt_len;
+    check_pkt_larger->dst = expr_resolve_field(&cipl->dst);
+}
+
+static void
+ovnact_check_pkt_larger_free(struct ovnact_check_pkt_larger *cipl OVS_UNUSED)
+{
+}
+
 /* Parses an assignment or exchange or put_dhcp_opts action. */
 static void
 parse_set_action(struct action_context *ctx)
@@ -2388,6 +2437,10 @@  parse_set_action(struct action_context *ctx)
                 && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
             parse_put_nd_ra_opts(ctx, &lhs,
                                  ovnact_put_PUT_ND_RA_OPTS(ctx->ovnacts));
+        } else if (!strcmp(ctx->lexer->token.s, "check_pkt_larger")
+                && lexer_lookahead(ctx->lexer) == LEX_T_LPAREN) {
+            parse_check_pkt_larger(ctx, &lhs,
+                                   ovnact_put_CHECK_PKT_LARGER(ctx->ovnacts));
         } else {
             parse_assignment_action(ctx, false, &lhs);
         }
diff --git a/ovn/ovn-sb.xml b/ovn/ovn-sb.xml
index 0d35fe4fc..9d611c9ab 100644
--- a/ovn/ovn-sb.xml
+++ b/ovn/ovn-sb.xml
@@ -1766,6 +1766,27 @@ 
 
           <p><b>Example:</b> <code>set_meter(100, 1000);</code></p>
         </dd>
+
+        <dt><code><var>R</var> = check_pkt_larger(<var>L</var>)</code></dt>
+        <dd>
+          <p>
+            <b>Parameters</b>: packet length <var>L</var> to check for
+            in bytes.
+          </p>
+
+          <p>
+            <b>Result</b>: stored to a 1-bit subfield <var>R</var>.
+          </p>
+
+          <p>
+            This is a logical equivalent of the OpenFlow
+            <code>check_pkt_larger</code> action. If the packet is larger
+            than the length specified in <var>L</var>, it stores 1 in the
+            subfield <var>R</var>.
+          </p>
+
+          <p><b>Example: </b><code>reg0[6] = check_pkt_larger(1000);</code></p>
+        </dd>
       </dl>
 
       <dl>
diff --git a/ovn/utilities/ovn-trace.c b/ovn/utilities/ovn-trace.c
index 28e2bb075..9718077aa 100644
--- a/ovn/utilities/ovn-trace.c
+++ b/ovn/utilities/ovn-trace.c
@@ -2134,8 +2134,10 @@  trace_actions(const struct ovnact *ovnacts, size_t ovnacts_len,
         case OVNACT_OVNFIELD_LOAD:
             execute_ovnfield_load(ovnact_get_OVNFIELD_LOAD(a), super);
             break;
-        }
 
+        case OVNACT_CHECK_PKT_LARGER:
+            break;
+        }
     }
     ds_destroy(&s);
 }
diff --git a/tests/ovn.at b/tests/ovn.at
index 92a6bed26..043697120 100644
--- a/tests/ovn.at
+++ b/tests/ovn.at
@@ -1341,6 +1341,16 @@  ip4.src <-> ip6.src[0..31];
     encodes as push:NXM_NX_IPV6_SRC[0..31],push:NXM_OF_IP_SRC[],pop:NXM_NX_IPV6_SRC[0..31],pop:NXM_OF_IP_SRC[]
     has prereqs eth.type == 0x800 && eth.type == 0x86dd
 
+# check_pkt_larger
+reg0[0] = check_pkt_larger(1500);
+    encodes as check_pkt_larger(1500)->NXM_NX_XXREG0[96]
+
+reg0 = check_pkt_larger(1500);
+    Cannot use 32-bit field reg0[0..31] where 1-bit field is required.
+
+reg0 = check_pkt_larger(foo);
+    Syntax error at `foo' expecting `;'.
+
 # Miscellaneous negative tests.
 ;
     Syntax error at `;'.