[ovs-dev] [PATCH 3/4] ofp-actions: Add support for conntrack timeout

Yi-Hung Wei yihung.wei at gmail.com
Fri May 3 21:56:39 UTC 2019


This patch adds support for specifying a timeout policy for a
connection in connection tracking system. The timeout policy
is attached to a connection when the connection is first committed
to conntrack.

Currently, this feature is available in Linux kernel datapath.
Here is an example of configuring a timeout policy in Linux kernel
with nfct, and sample flows of attaching the timeout policy with a
connection.

    $ nfct add timeout ovs_timeout_1 inet icmp timeout 10

    table=0,priority=1,action=drop
    table=0,arp,action=normal
    table=0,in_port=1,icmp,action=ct(commit,timeout=1),2
    table=0,in_port=2,icmp,action=ct(table=1)
    table=1,in_port=2,icmp,ct_state=+trk+est,action=1

Signed-off-by: Yi-Hung Wei <yihung.wei at gmail.com>
---
 include/openvswitch/ofp-actions.h |  1 +
 lib/dpif-netdev.c                 |  3 +++
 lib/odp-util.c                    | 29 +++++++++++++++++++++++++----
 lib/ofp-actions.c                 | 24 +++++++++++++++++++++++-
 lib/ovs-actions.xml               | 29 +++++++++++++++++++++++++++++
 ofproto/ofproto-dpif-xlate.c      | 12 ++++++++++++
 tests/odp.at                      |  1 +
 tests/ofp-actions.at              |  3 +++
 8 files changed, 97 insertions(+), 5 deletions(-)

diff --git a/include/openvswitch/ofp-actions.h b/include/openvswitch/ofp-actions.h
index 436c4aadf548..982ec6cbd965 100644
--- a/include/openvswitch/ofp-actions.h
+++ b/include/openvswitch/ofp-actions.h
@@ -691,6 +691,7 @@ struct ofpact_conntrack {
         uint16_t zone_imm;
         struct mf_subfield zone_src;
         uint16_t alg;
+        uint16_t timeout;
         uint8_t recirc_table;
     );
     struct ofpact actions[0];
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index f1422b2b1fbd..240c53b8bbc5 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -7132,6 +7132,9 @@ dp_execute_cb(void *aux_, struct dp_packet_batch *packets_,
                 /* Silently ignored, as userspace datapath does not generate
                  * netlink events. */
                 break;
+            case OVS_CT_ATTR_TIMEOUT:
+                /* Userspace datapath does not support customized timeout. */
+                break;
             case OVS_CT_ATTR_NAT: {
                 const struct nlattr *b_nest;
                 unsigned int left_nest;
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 1b2347d6f469..c9c649be289e 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -923,6 +923,8 @@ static const struct nl_policy ovs_conntrack_policy[] = {
     [OVS_CT_ATTR_HELPER] = { .type = NL_A_STRING, .optional = true,
                              .min_len = 1, .max_len = 16 },
     [OVS_CT_ATTR_NAT] = { .type = NL_A_UNSPEC, .optional = true },
+    [OVS_CT_ATTR_TIMEOUT] = { .type = NL_A_STRING, .optional = true,
+                              .min_len = 1, .max_len = 32 },
 };
 
 static void
@@ -934,7 +936,7 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr)
         ovs_32aligned_u128 mask;
     } *label;
     const uint32_t *mark;
-    const char *helper;
+    const char *helper, *timeout;
     uint16_t zone;
     bool commit, force;
     const struct nlattr *nat;
@@ -950,10 +952,12 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr)
     mark = a[OVS_CT_ATTR_MARK] ? nl_attr_get(a[OVS_CT_ATTR_MARK]) : NULL;
     label = a[OVS_CT_ATTR_LABELS] ? nl_attr_get(a[OVS_CT_ATTR_LABELS]): NULL;
     helper = a[OVS_CT_ATTR_HELPER] ? nl_attr_get(a[OVS_CT_ATTR_HELPER]) : NULL;
+    timeout = a[OVS_CT_ATTR_TIMEOUT] ?
+                nl_attr_get(a[OVS_CT_ATTR_TIMEOUT]) : NULL;
     nat = a[OVS_CT_ATTR_NAT];
 
     ds_put_format(ds, "ct");
-    if (commit || force || zone || mark || label || helper || nat) {
+    if (commit || force || zone || mark || label || helper || timeout || nat) {
         ds_put_cstr(ds, "(");
         if (commit) {
             ds_put_format(ds, "commit,");
@@ -976,6 +980,9 @@ format_odp_conntrack_action(struct ds *ds, const struct nlattr *attr)
         if (helper) {
             ds_put_format(ds, "helper=%s,", helper);
         }
+        if (timeout) {
+            ds_put_format(ds, "timeout=%s", timeout);
+        }
         if (nat) {
             format_odp_ct_nat(ds, nat);
         }
@@ -1902,8 +1909,8 @@ parse_conntrack_action(const char *s_, struct ofpbuf *actions)
     const char *s = s_;
 
     if (ovs_scan(s, "ct")) {
-        const char *helper = NULL;
-        size_t helper_len = 0;
+        const char *helper = NULL, *timeout = NULL;
+        size_t helper_len = 0, timeout_len = 0;
         bool commit = false;
         bool force_commit = false;
         uint16_t zone = 0;
@@ -1980,6 +1987,16 @@ find_end:
                     s += helper_len;
                     continue;
                 }
+                if (ovs_scan(s, "timeout=%n", &n)) {
+                    s += n;
+                    timeout_len = strcspn(s, delimiters_end);
+                    if (!timeout_len || timeout_len > 31) {
+                        return -EINVAL;
+                    }
+                    timeout = s;
+                    s += timeout_len;
+                    continue;
+                }
 
                 n = scan_ct_nat(s, &nat_params);
                 if (n > 0) {
@@ -2020,6 +2037,10 @@ find_end:
             nl_msg_put_string__(actions, OVS_CT_ATTR_HELPER, helper,
                                 helper_len);
         }
+        if (timeout) {
+            nl_msg_put_string__(actions, OVS_CT_ATTR_TIMEOUT, timeout,
+                                timeout_len);
+        }
         if (have_nat) {
             nl_msg_put_ct_nat(&nat_params, actions);
         }
diff --git a/lib/ofp-actions.c b/lib/ofp-actions.c
index 1a24063d087c..4d7c4a211a84 100644
--- a/lib/ofp-actions.c
+++ b/lib/ofp-actions.c
@@ -6416,6 +6416,18 @@ check_DEBUG_SLOW(const struct ofpact_null *a OVS_UNUSED,
  *      NXM_NX_CT_STATE field for such connections if the 'recirc_table' is
  *      specified.
  *
+ * The "timeout" specifies a timeout policy which the tracking is associated:
+ *
+ *      The 'timeout' is a 16-bit number.
+ *
+ *      If 'timeout' is zero, then the conntrack entry will be associated with
+ *      the datapath's default timeout policy
+ *
+ *      If 'timeout' is non-zero, the datapath will map 'timeout' to a
+ *      preconfigured timeout policy in the datapath, and associated
+ *      the connection with the preconfigured timeout policy.
+ *      Refer to ovs-actions (7) for more details.
+ *
  * Zero or more actions may immediately follow this action. These actions will
  * be executed within the context of the connection tracker, and they require
  * NX_CT_F_COMMIT flag be set.
@@ -6434,7 +6446,9 @@ struct nx_action_conntrack {
     };
     uint8_t recirc_table;       /* Recirculate to a specific table, or
                                    NX_CT_RECIRC_NONE for no recirculation. */
-    uint8_t pad[3];             /* Zeroes */
+    uint8_t pad[1];             /* Zero */
+    ovs_be16 timeout;           /* Timeout policy to associated with.
+                                 * 0 indicates default timeout policy. */
     ovs_be16 alg;               /* Well-known port number for the protocol.
                                  * 0 indicates no ALG is required. */
     /* Followed by a sequence of zero or more OpenFlow actions. The length of
@@ -6500,6 +6514,7 @@ decode_NXAST_RAW_CT(const struct nx_action_conntrack *nac,
     }
     conntrack->recirc_table = nac->recirc_table;
     conntrack->alg = ntohs(nac->alg);
+    conntrack->timeout = ntohs(nac->timeout);
 
     ofpbuf_pull(out, sizeof(*conntrack));
 
@@ -6559,6 +6574,7 @@ encode_CT(const struct ofpact_conntrack *conntrack,
     }
     nac->recirc_table = conntrack->recirc_table;
     nac->alg = htons(conntrack->alg);
+    nac->timeout = htons(conntrack->timeout);
 
     len = ofpacts_put_openflow_actions(conntrack->actions,
                                        ofpact_ct_get_action_len(conntrack),
@@ -6611,6 +6627,8 @@ parse_CT(char *arg, const struct ofpact_parse_params *pp)
             }
         } else if (!strcmp(key, "alg")) {
             error = str_to_connhelper(value, &oc->alg);
+        } else if (!strcmp(key, "timeout")) {
+            error = str_to_u16(value, "timeout", &oc->timeout);
         } else if (!strcmp(key, "nat")) {
             const size_t nat_offset = ofpacts_pull(pp->ofpacts);
 
@@ -6715,6 +6733,10 @@ format_CT(const struct ofpact_conntrack *a,
         ds_put_format(fp->s, "%s),%s", colors.paren, colors.end);
     }
     format_alg(a->alg, fp->s);
+    if (a->timeout) {
+        ds_put_format(fp->s, "%stimeout=%s%d", colors.paren, colors.end,
+                      a->timeout);
+    }
     ds_chomp(fp->s, ',');
     ds_put_format(fp->s, "%s)%s", colors.paren, colors.end);
 }
diff --git a/lib/ovs-actions.xml b/lib/ovs-actions.xml
index cfd9b81be604..7aba82e84d53 100644
--- a/lib/ovs-actions.xml
+++ b/lib/ovs-actions.xml
@@ -1855,6 +1855,35 @@ $ ovs-ofctl -O OpenFlow10 add-flow br0 actions=mod_nw_src:1.2.3.4
             <code>ct(alg=</code>...<code>)</code>).
           </p>
         </dd>
+        <dt><code>timeout=<var>timeout</var></code></dt>
+        <dd>
+          <p>
+            Specify a timeout policy to associate with the connection.
+            The timeout policy is preconfigured in the datapath, and it
+            is used to associated with connection when the connection is
+            committed. <var>timeout</var> is a 16-bit number.
+            By default, or with <code>timeout=0</code>, the datapath associates
+            the connection with the datapath's default timeout.
+          </p>
+
+          <p>
+            If <var>timeout</var> is non-zero, in Linux datapath, it associates
+            the connection with timeout policy:
+            <code>ovs_timeout_<var>timeout</var></code> (i.e. it associates
+            the connection with ovs_timeout_3 if <code>timeout=3</code>).
+            If the datapath fails to associate with the specified timeout
+            policy, it uses the datapath's default timeout.
+            Refer to <code>nfct</code>(8) for more details on configuring
+            timeout policy on Linux kernel datapath. The conntrack
+            <code>timeout</code> support on Linux kernel datapath was
+            introduced in 2.11.90.
+          </p>
+
+          <p>
+            Currently, userspace datapath does support conntrack
+            <code>timeout</code>.
+          </p>
+        </dd>
       </dl>
 
       <p>
diff --git a/ofproto/ofproto-dpif-xlate.c b/ofproto/ofproto-dpif-xlate.c
index 5cee37f7bf9e..d49851653226 100644
--- a/ofproto/ofproto-dpif-xlate.c
+++ b/ofproto/ofproto-dpif-xlate.c
@@ -5962,6 +5962,17 @@ put_ct_helper(struct xlate_ctx *ctx,
 }
 
 static void
+put_ct_timeout(struct ofpbuf *odp_actions, struct ofpact_conntrack *ofc)
+{
+    if (ofc->timeout) {
+        struct ds s = DS_EMPTY_INITIALIZER;
+        ds_put_format(&s, "%s%d", "ovs_timeout_", ofc->timeout);
+        nl_msg_put_string(odp_actions, OVS_CT_ATTR_TIMEOUT, ds_cstr(&s));
+        ds_destroy(&s);
+    }
+}
+
+static void
 put_ct_nat(struct xlate_ctx *ctx)
 {
     struct ofpact_nat *ofn = ctx->ct_nat_action;
@@ -6056,6 +6067,7 @@ compose_conntrack_action(struct xlate_ctx *ctx, struct ofpact_conntrack *ofc,
     put_ct_mark(&ctx->xin->flow, ctx->odp_actions, ctx->wc);
     put_ct_label(&ctx->xin->flow, ctx->odp_actions, ctx->wc);
     put_ct_helper(ctx, ctx->odp_actions, ofc);
+    put_ct_timeout(ctx->odp_actions, ofc);
     put_ct_nat(ctx);
     ctx->ct_nat_action = NULL;
     nl_msg_end_nested(ctx->odp_actions, ct_offset);
diff --git a/tests/odp.at b/tests/odp.at
index 8e4ba4615548..533260dca5a7 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -345,6 +345,7 @@ ct(commit,mark=0xa0a0a0a0/0xfefefefe)
 ct(commit,label=0x1234567890abcdef1234567890abcdef/0xf1f2f3f4f5f6f7f8f9f0fafbfcfdfeff)
 ct(commit,helper=ftp)
 ct(commit,helper=tftp)
+ct(commit,timeout=1)
 ct(nat)
 ct(commit,nat(src))
 ct(commit,nat(dst))
diff --git a/tests/ofp-actions.at b/tests/ofp-actions.at
index 746af4f8adf9..cc7354f26dca 100644
--- a/tests/ofp-actions.at
+++ b/tests/ofp-actions.at
@@ -164,6 +164,9 @@ ffff 0018 00002320 0023 0001 00000000 0000 FF 000000 0000
 # actions=ct(commit,force)
 ffff 0018 00002320 0023 0003 00000000 0000 FF 000000 0000
 
+# actions=ct(commit,timeout=17)
+ffff 0018 00002320 0023 0001 00000000 0000 FF 00 0011 0000
+
 # bad OpenFlow10 actions: OFPBAC_BAD_ARGUMENT
 ffff 0018 00002320 0023 0002 00000000 0000 FF 000000 0000
 
-- 
2.7.4



More information about the dev mailing list