The new odp sample attributes allow userspace to specify a group_id and
user-defined cookie to be passed down to psample.

Add support for parsing and formatting such action.

Signed-off-by: Adrian Moreno <amore...@redhat.com>
---
 include/linux/openvswitch.h  |  49 +++++++++---
 lib/odp-execute.c            |   3 +
 lib/odp-util.c               | 150 ++++++++++++++++++++++++++---------
 ofproto/ofproto-dpif-ipfix.c |   2 +
 python/ovs/flow/odp.py       |   2 +
 tests/odp.at                 |   5 ++
 6 files changed, 163 insertions(+), 48 deletions(-)

diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index d9fb991ef..3e748405c 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -696,6 +696,7 @@ enum ovs_flow_attr {
 #define OVS_UFID_F_OMIT_MASK     (1 << 1)
 #define OVS_UFID_F_OMIT_ACTIONS  (1 << 2)
 
+#define OVS_PSAMPLE_COOKIE_MAX_SIZE 16
 /**
  * enum ovs_sample_attr - Attributes for %OVS_ACTION_ATTR_SAMPLE action.
  * @OVS_SAMPLE_ATTR_PROBABILITY: 32-bit fraction of packets to sample with
@@ -703,15 +704,27 @@ enum ovs_flow_attr {
  * %UINT32_MAX samples all packets and intermediate values sample intermediate
  * fractions of packets.
  * @OVS_SAMPLE_ATTR_ACTIONS: Set of actions to execute in sampling event.
- * Actions are passed as nested attributes.
+ * Actions are passed as nested attributes. Optional if
+ * OVS_SAMPLE_ATTR_PSAMPLE_GROUP is set.
+ * @OVS_SAMPLE_ATTR_PSAMPLE_GROUP: A 32-bit number to be used as psample group.
+ * Optional if OVS_SAMPLE_ATTR_ACTIONS is set.
+ * @OVS_SAMPLE_ATTR_PSAMPLE_COOKIE: A variable-length binary cookie that, if
+ * provided, will be copied to the psample cookie.
  *
- * Executes the specified actions with the given probability on a per-packet
- * basis.
+ * Either OVS_SAMPLE_ATTR_PSAMPLE_GROUP or OVS_SAMPLE_ATTR_ACTIONS must be
+ * specified.
+ *
+ * Executes the specified actions and/or sends the packet to psample
+ * with the given probability on a per-packet basis.
  */
 enum ovs_sample_attr {
        OVS_SAMPLE_ATTR_UNSPEC,
-       OVS_SAMPLE_ATTR_PROBABILITY, /* u32 number */
-       OVS_SAMPLE_ATTR_ACTIONS,     /* Nested OVS_ACTION_ATTR_* attributes. */
+       OVS_SAMPLE_ATTR_PROBABILITY,    /* u32 number */
+       OVS_SAMPLE_ATTR_ACTIONS,        /* Nested OVS_ACTION_ATTR_
+                                        * attributes.
+                                        */
+       OVS_SAMPLE_ATTR_PSAMPLE_GROUP,  /* u32 number */
+       OVS_SAMPLE_ATTR_PSAMPLE_COOKIE, /* binary */
        __OVS_SAMPLE_ATTR_MAX,
 
 #ifdef __KERNEL__
@@ -722,13 +735,27 @@ enum ovs_sample_attr {
 #define OVS_SAMPLE_ATTR_MAX (__OVS_SAMPLE_ATTR_MAX - 1)
 
 #ifdef __KERNEL__
+
+/* Definition for flags in struct sample_arg. */
+enum {
+       /* When actions in sample will not change the flows. */
+       OVS_SAMPLE_ARG_FLAG_EXEC = 1 << 0,
+       /* When set, the packet will be sent to psample. */
+       OVS_SAMPLE_ARG_FLAG_PSAMPLE = 1 << 1,
+};
+
 struct sample_arg {
-       bool exec;                   /* When true, actions in sample will not
-                                     * change flow keys. False otherwise.
-                                     */
-       u32  probability;            /* Same value as
-                                     * 'OVS_SAMPLE_ATTR_PROBABILITY'.
-                                     */
+       u16 flags;             /* Flags that modify the behavior of the
+                               * action. See SAMPLE_ARG_FLAG_*
+                               */
+       u32  probability;       /* Same value as
+                                * 'OVS_SAMPLE_ATTR_PROBABILITY'.
+                                */
+       u32  group_id;          /* Same value as
+                                * 'OVS_SAMPLE_ATTR_PSAMPLE_GROUP'.
+                                */
+       u8  cookie_len;         /* Length of psample cookie */
+       char cookie[OVS_PSAMPLE_COOKIE_MAX_SIZE]; /* psample cookie data. */
 };
 #endif
 
diff --git a/lib/odp-execute.c b/lib/odp-execute.c
index 081e4d432..d8ee93429 100644
--- a/lib/odp-execute.c
+++ b/lib/odp-execute.c
@@ -716,6 +716,9 @@ odp_execute_sample(void *dp, struct dp_packet *packet, bool 
steal,
             subactions = a;
             break;
 
+        /* Ignored in userspace datapath. */
+        case OVS_SAMPLE_ATTR_PSAMPLE_GROUP:
+        case OVS_SAMPLE_ATTR_PSAMPLE_COOKIE:
         case OVS_SAMPLE_ATTR_UNSPEC:
         case __OVS_SAMPLE_ATTR_MAX:
         default:
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 21f34d955..611b5229e 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -227,12 +227,16 @@ format_odp_sample_action(struct ds *ds, const struct 
nlattr *attr,
 {
     static const struct nl_policy ovs_sample_policy[] = {
         [OVS_SAMPLE_ATTR_PROBABILITY] = { .type = NL_A_U32 },
-        [OVS_SAMPLE_ATTR_ACTIONS] = { .type = NL_A_NESTED }
+        [OVS_SAMPLE_ATTR_ACTIONS] = { .type = NL_A_NESTED,
+                                      .optional = true },
+        [OVS_SAMPLE_ATTR_PSAMPLE_GROUP] = { .type = NL_A_U32,
+                                            .optional = true },
+        [OVS_SAMPLE_ATTR_PSAMPLE_COOKIE] = { .type = NL_A_UNSPEC,
+                                             .optional = true }
     };
     struct nlattr *a[ARRAY_SIZE(ovs_sample_policy)];
+    const struct nlattr *nla;
     double percentage;
-    const struct nlattr *nla_acts;
-    int len;
 
     ds_put_cstr(ds, "sample");
 
@@ -244,13 +248,33 @@ format_odp_sample_action(struct ds *ds, const struct 
nlattr *attr,
     percentage = (100.0 * nl_attr_get_u32(a[OVS_SAMPLE_ATTR_PROBABILITY])) /
                         UINT32_MAX;
 
-    ds_put_format(ds, "(sample=%.1f%%,", percentage);
+    ds_put_format(ds, "(sample=%.1f%%", percentage);
 
-    ds_put_cstr(ds, "actions(");
-    nla_acts = nl_attr_get(a[OVS_SAMPLE_ATTR_ACTIONS]);
-    len = nl_attr_get_size(a[OVS_SAMPLE_ATTR_ACTIONS]);
-    format_odp_actions(ds, nla_acts, len, portno_names);
-    ds_put_format(ds, "))");
+    nla = a[OVS_SAMPLE_ATTR_PSAMPLE_GROUP];
+    if (nla) {
+        ds_put_format(ds, ",group_id=%d", nl_attr_get_u32(nla));
+
+        nla = a[OVS_SAMPLE_ATTR_PSAMPLE_COOKIE];
+
+        if (nla) {
+            size_t i;
+            const uint8_t *c = nl_attr_get(nla);
+            ds_put_cstr(ds, ",cookie=");
+            for (i = 0; i < nl_attr_get_size(nla); i++) {
+                ds_put_format(ds, "%02x", c[i]);
+            }
+        }
+    }
+
+    nla = a[OVS_SAMPLE_ATTR_ACTIONS];
+    if (nla) {
+        ds_put_cstr(ds, ",actions(");
+        format_odp_actions(ds, nl_attr_get(nla), nl_attr_get_size(nla),
+                           portno_names);
+        ds_put_format(ds, "))");
+    } else {
+        ds_put_format(ds, ")");
+    }
 }
 
 static void
@@ -1348,6 +1372,84 @@ format_odp_actions(struct ds *ds, const struct nlattr 
*actions,
     }
 }
 
+static int
+parse_action_list(struct parse_odp_context *context, const char *s,
+                  struct ofpbuf *actions);
+static int
+parse_odp_sample_action(const char *s, struct parse_odp_context *context,
+                        struct ofpbuf *actions)
+{
+    double percentage;
+    uint32_t group_id;
+    size_t sample_ofs, actions_ofs;
+    double probability;
+    int parsed = 0;
+    int n;
+
+    if (!ovs_scan(s, "sample(sample=%lf%%,%n", &percentage, &parsed)) {
+        return -EINVAL;
+    }
+
+    probability = floor(UINT32_MAX * (percentage / 100.0) + .5);
+    sample_ofs = nl_msg_start_nested(actions, OVS_ACTION_ATTR_SAMPLE);
+    nl_msg_put_u32(actions, OVS_SAMPLE_ATTR_PROBABILITY,
+                   (probability <= 0 ? 0
+                    : probability >= UINT32_MAX ? UINT32_MAX
+                    : probability));
+
+    if (ovs_scan(s + parsed, "group_id=%"PRIu32"%n", &group_id, &n)) {
+        parsed += n;
+
+        nl_msg_put_u32(actions, OVS_SAMPLE_ATTR_PSAMPLE_GROUP, group_id);
+
+        if (ovs_scan(s + parsed, ",cookie=%n", &n)) {
+            struct ofpbuf buf;
+            size_t size;
+            char *end;
+
+            parsed += n;
+            ofpbuf_init(&buf, OVS_PSAMPLE_COOKIE_MAX_SIZE);
+
+            end = ofpbuf_put_hex(&buf, s + parsed, &size);
+            if (!end ||
+                size > OVS_PSAMPLE_COOKIE_MAX_SIZE ||
+               (end[0] != ')' && end[0] != ',')) {
+                ofpbuf_uninit(&buf);
+                return -EINVAL;
+            }
+
+            nl_msg_put_unspec(actions, OVS_SAMPLE_ATTR_PSAMPLE_COOKIE,
+                              buf.data, buf.size);
+
+            ofpbuf_uninit(&buf);
+            parsed = end - s;
+        }
+        if (s[parsed] == ')') {
+            nl_msg_end_nested(actions, sample_ofs);
+            return parsed + 1;
+        } else if (s[parsed] == ',') {
+            parsed += 1;
+        } else {
+            return -EINVAL;
+        }
+    }
+
+    if (ovs_scan(s + parsed, "actions(%n", &n)) {
+        parsed += n;
+        actions_ofs = nl_msg_start_nested(actions, OVS_SAMPLE_ATTR_ACTIONS);
+        int retval = parse_action_list(context, s + parsed, actions);
+        if (retval < 0) {
+            return retval;
+        }
+        parsed += retval;
+        nl_msg_end_nested(actions, actions_ofs);
+        nl_msg_end_nested(actions, sample_ofs);
+        return s[parsed + 1] == ')' ? parsed + 2 : -EINVAL;
+    }
+
+    return -EINVAL;
+}
+
 /* Separate out parse_odp_userspace_action() function. */
 static int
 parse_odp_userspace_action(const char *s, struct ofpbuf *actions)
@@ -2561,34 +2663,8 @@ parse_odp_action__(struct parse_odp_context *context, 
const char *s,
     }
 
     {
-        double percentage;
-        int n = -1;
-
-        if (ovs_scan(s, "sample(sample=%lf%%,actions(%n", &percentage, &n)
-            && percentage >= 0. && percentage <= 100.0) {
-            size_t sample_ofs, actions_ofs;
-            double probability;
-
-            probability = floor(UINT32_MAX * (percentage / 100.0) + .5);
-            sample_ofs = nl_msg_start_nested(actions, OVS_ACTION_ATTR_SAMPLE);
-            nl_msg_put_u32(actions, OVS_SAMPLE_ATTR_PROBABILITY,
-                           (probability <= 0 ? 0
-                            : probability >= UINT32_MAX ? UINT32_MAX
-                            : probability));
-
-            actions_ofs = nl_msg_start_nested(actions,
-                                              OVS_SAMPLE_ATTR_ACTIONS);
-            int retval = parse_action_list(context, s + n, actions);
-            if (retval < 0) {
-                return retval;
-            }
-
-
-            n += retval;
-            nl_msg_end_nested(actions, actions_ofs);
-            nl_msg_end_nested(actions, sample_ofs);
-
-            return s[n + 1] == ')' ? n + 2 : -EINVAL;
+        if (ovs_scan(s, "sample(")) {
+            return parse_odp_sample_action(s, context, actions);
         }
     }
 
diff --git a/ofproto/ofproto-dpif-ipfix.c b/ofproto/ofproto-dpif-ipfix.c
index cd65dae7e..407b2b38a 100644
--- a/ofproto/ofproto-dpif-ipfix.c
+++ b/ofproto/ofproto-dpif-ipfix.c
@@ -3064,6 +3064,8 @@ dpif_ipfix_read_sample_actions(const struct flow *flow,
                                     &sample_actions);
             break;
 
+        case OVS_SAMPLE_ATTR_PSAMPLE_GROUP:
+        case OVS_SAMPLE_ATTR_PSAMPLE_COOKIE:
         case OVS_SAMPLE_ATTR_UNSPEC:
         case __OVS_SAMPLE_ATTR_MAX:
         default:
diff --git a/python/ovs/flow/odp.py b/python/ovs/flow/odp.py
index 7d9b165d4..bc0495eb4 100644
--- a/python/ovs/flow/odp.py
+++ b/python/ovs/flow/odp.py
@@ -349,6 +349,8 @@ class ODPFlow(Flow):
             KVDecoders(
                 {
                     "sample": (lambda x: float(x.strip("%"))),
+                    "group_id": decode_int,
+                    "cookie": decode_default,
                     "actions": nested_kv_decoder(
                         KVDecoders(
                             decoders=_decoders,
diff --git a/tests/odp.at b/tests/odp.at
index ba20604e4..4a2435c97 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -327,6 +327,9 @@ push_vlan(tpid=0x9100,vid=13,pcp=5)
 push_vlan(tpid=0x9100,vid=13,pcp=5,cfi=0)
 pop_vlan
 sample(sample=9.7%,actions(1,2,3,push_vlan(vid=1,pcp=2)))
+sample(sample=9.7%,group_id=25)
+sample(sample=9.7%,group_id=12,cookie=0102)
+sample(sample=9.7%,group_id=12,cookie=0102030405060708090a0b0c0d0e0f,actions(1,2,3,push_vlan(vid=1,pcp=2)))
 
set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(df|csum|key)))
 
set(tunnel(tun_id=0xabcdef1234567890,src=1.1.1.1,dst=2.2.2.2,ttl=64,flags(key)))
 tnl_pop(4)
@@ -406,11 +409,13 @@ AT_DATA([actions.txt], [dnl
 encap_nsh@:{@
 
tnl_push(tnl_port(6),header(size=94,type=112,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=43,tclass=0x0,hlimit=64),srv6(segments_left=2,segs(2001:cafe::90,2001:cafe::91))),out_port(1))
 
tnl_push(tnl_port(6),header(size=126,type=112,eth(dst=f8:bc:12:44:34:b6,src=f8:bc:12:46:58:e0,dl_type=0x86dd),ipv6(src=2001:cafe::88,dst=2001:cafe::92,label=0,proto=43,tclass=0x0,hlimit=64),srv6(segments_left=2,segs(2001:cafe::90,2001:cafe::91,2001:cafe::92,2001:cafe::93))),out_port(1))
+sample(sample=9.7%,group_id=12,cookie=0102030405060708090a0b0c0d0e0f0f0f)
 ])
 AT_CHECK_UNQUOTED([ovstest test-odp parse-actions < actions.txt], [0], [dnl
 odp_actions_from_string: error
 odp_actions_from_string: error
 odp_actions_from_string: error
+odp_actions_from_string: error
 ])
 AT_CLEANUP
 
-- 
2.44.0

_______________________________________________
dev mailing list
d...@openvswitch.org
https://mail.openvswitch.org/mailman/listinfo/ovs-dev

Reply via email to