Following patch adds skb-priority to flow key. So userspace will know
what was priority when packet arrived and we can remove the pop/reset
priority action. It's no longer necessary to have a special action for
pop that is based on the kernel remembering original skb->priority.
Userspace can just emit a set priority action with the original value.

Since the priority field is a match field with just a normal set action,
we can convert it into the new model for actions that are based on
matches.

Signed-off-by: Pravin B Shelar <pshe...@nicira.com>
Bug #7715
---
 datapath/actions.c          |   13 +++-------
 datapath/datapath.c         |   11 ++------
 datapath/flow.c             |   24 ++++++++++++++++++-
 datapath/flow.h             |    8 ++++--
 include/linux/openvswitch.h |    6 +----
 lib/classifier.c            |    4 +++
 lib/dpif-netdev.c           |    7 +----
 lib/dpif-provider.h         |    3 +-
 lib/dpif.c                  |    6 ++--
 lib/flow.h                  |    8 ++++--
 lib/odp-util.c              |   35 ++++++++++++++++++++++------
 lib/odp-util.h              |    7 +++--
 lib/ofp-util.c              |    1 +
 ofproto/ofproto-dpif.c      |   52 ++++++++++++++++++++----------------------
 tests/odp.at                |    4 +++
 tests/test-classifier.c     |    1 +
 16 files changed, 112 insertions(+), 78 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 8ca243d..4db2563 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -314,6 +314,10 @@ static int execute_set_action(struct sk_buff *skb,
        int err = 0;
 
        switch (nla_type(nested_attr)) {
+       case OVS_KEY_ATTR_PRIORITY:
+               skb->priority = nla_get_u32(nested_attr);
+               break;
+
        case OVS_KEY_ATTR_TUN_ID:
                OVS_CB(skb)->tun_id = nla_get_be64(nested_attr);
                break;
@@ -347,7 +351,6 @@ static int do_execute_actions(struct datapath *dp, struct 
sk_buff *skb,
         * then freeing the original skbuff is wasteful.  So the following code
         * is slightly obscure just to avoid that. */
        int prev_port = -1;
-       u32 priority = skb->priority;
        const struct nlattr *a;
        int rem;
 
@@ -385,14 +388,6 @@ static int do_execute_actions(struct datapath *dp, struct 
sk_buff *skb,
                        err = execute_set_action(skb, nla_data(a));
                        break;
 
-               case OVS_ACTION_ATTR_SET_PRIORITY:
-                       skb->priority = nla_get_u32(a);
-                       break;
-
-               case OVS_ACTION_ATTR_POP_PRIORITY:
-                       skb->priority = priority;
-                       break;
-
                case OVS_ACTION_ATTR_SAMPLE:
                        err = sample(dp, skb, a);
                        break;
diff --git a/datapath/datapath.c b/datapath/datapath.c
index be90d54..4809d4b 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -558,6 +558,7 @@ static int validate_action_key(const struct nlattr *a,
        const struct ovs_key_ipv4 *ipv4_key;
        const struct ovs_key_8021q *q_key;
 
+       case ACTION(OVS_ACTION_ATTR_SET, OVS_KEY_ATTR_PRIORITY):
        case ACTION(OVS_ACTION_ATTR_SET, OVS_KEY_ATTR_TUN_ID):
        case ACTION(OVS_ACTION_ATTR_SET, OVS_KEY_ATTR_ETHERNET):
                break;
@@ -652,8 +653,6 @@ static int validate_actions(const struct nlattr *attr,
                        [OVS_ACTION_ATTR_PUSH] = (u32)-1,
                        [OVS_ACTION_ATTR_POP] = 2,
                        [OVS_ACTION_ATTR_SET] = (u32)-1,
-                       [OVS_ACTION_ATTR_SET_PRIORITY] = 4,
-                       [OVS_ACTION_ATTR_POP_PRIORITY] = 0,
                        [OVS_ACTION_ATTR_SAMPLE] = (u32)-1
                };
                int type = nla_type(a);
@@ -667,11 +666,6 @@ static int validate_actions(const struct nlattr *attr,
                case OVS_ACTION_ATTR_UNSPEC:
                        return -EINVAL;
 
-               case OVS_ACTION_ATTR_SET_PRIORITY:
-               case OVS_ACTION_ATTR_POP_PRIORITY:
-                       /* No validation needed. */
-                       break;
-
                case OVS_ACTION_ATTR_USERSPACE:
                        err = validate_userspace(a);
                        if (err)
@@ -770,7 +764,8 @@ static int ovs_packet_cmd_execute(struct sk_buff *skb, 
struct genl_info *info)
        if (err)
                goto err_flow_put;
 
-       err = flow_metadata_from_nlattrs(&flow->key.eth.in_port,
+       err = flow_metadata_from_nlattrs(&flow->key.priority,
+                                        &flow->key.eth.in_port,
                                         &flow->key.eth.tun_id,
                                         a[OVS_PACKET_ATTR_KEY]);
        if (err)
diff --git a/datapath/flow.c b/datapath/flow.c
index b6023a0..98b6aec 100644
--- a/datapath/flow.c
+++ b/datapath/flow.c
@@ -638,6 +638,8 @@ int flow_extract(struct sk_buff *skb, u16 in_port, struct 
sw_flow_key *key,
        struct ethhdr *eth;
 
        memset(key, 0, sizeof(*key));
+
+       key->priority = skb->priority;
        key->eth.tun_id = OVS_CB(skb)->tun_id;
        key->eth.in_port = in_port;
 
@@ -849,6 +851,7 @@ static int parse_tos_frag(struct sw_flow_key *swkey, u8 
tos, u8 frag)
 
 /* The size of the argument for each %OVS_KEY_ATTR_* Netlink attribute.  */
 const u32 ovs_key_lens[OVS_KEY_ATTR_MAX + 1] = {
+       [OVS_KEY_ATTR_PRIORITY] = 4,
        [OVS_KEY_ATTR_TUN_ID] = 8,
        [OVS_KEY_ATTR_IN_PORT] = 4,
        [OVS_KEY_ATTR_ETHERNET] = sizeof(struct ovs_key_ethernet),
@@ -915,11 +918,17 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int 
*key_lenp,
 
 #define TRANSITION(PREV_TYPE, TYPE) (((PREV_TYPE) << 16) | (TYPE))
                switch (TRANSITION(prev_type, type)) {
+               case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_PRIORITY):
+                       swkey->priority = nla_get_u32(nla);
+                       break;
+
                case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_TUN_ID):
+               case TRANSITION(OVS_KEY_ATTR_PRIORITY, OVS_KEY_ATTR_TUN_ID):
                        swkey->eth.tun_id = nla_get_be64(nla);
                        break;
 
                case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_IN_PORT):
+               case TRANSITION(OVS_KEY_ATTR_PRIORITY, OVS_KEY_ATTR_IN_PORT):
                case TRANSITION(OVS_KEY_ATTR_TUN_ID, OVS_KEY_ATTR_IN_PORT):
                        if (nla_get_u32(nla) >= DP_MAX_PORTS)
                                goto invalid;
@@ -927,6 +936,7 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int 
*key_lenp,
                        break;
 
                case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_ETHERNET):
+               case TRANSITION(OVS_KEY_ATTR_PRIORITY, OVS_KEY_ATTR_ETHERNET):
                case TRANSITION(OVS_KEY_ATTR_TUN_ID, OVS_KEY_ATTR_ETHERNET):
                case TRANSITION(OVS_KEY_ATTR_IN_PORT, OVS_KEY_ATTR_ETHERNET):
                        eth_key = nla_data(nla);
@@ -1073,6 +1083,7 @@ int flow_from_nlattrs(struct sw_flow_key *swkey, int 
*key_lenp,
        case OVS_KEY_ATTR_UNSPEC:
                goto invalid;
 
+       case OVS_KEY_ATTR_PRIORITY:
        case OVS_KEY_ATTR_TUN_ID:
        case OVS_KEY_ATTR_IN_PORT:
                goto invalid;
@@ -1148,7 +1159,7 @@ ok:
  * get the metadata, that is, the parts of the flow key that cannot be
  * extracted from the packet itself.
  */
-int flow_metadata_from_nlattrs(u16 *in_port, __be64 *tun_id,
+int flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id,
                               const struct nlattr *attr)
 {
        const struct nlattr *nla;
@@ -1166,11 +1177,17 @@ int flow_metadata_from_nlattrs(u16 *in_port, __be64 
*tun_id,
                        return -EINVAL;
 
                switch (TRANSITION(prev_type, type)) {
+               case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_PRIORITY):
+                       *priority = nla_get_u32(nla);
+                       break;
+
                case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_TUN_ID):
+               case TRANSITION(OVS_KEY_ATTR_PRIORITY, OVS_KEY_ATTR_TUN_ID):
                        *tun_id = nla_get_be64(nla);
                        break;
 
                case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_IN_PORT):
+               case TRANSITION(OVS_KEY_ATTR_PRIORITY, OVS_KEY_ATTR_IN_PORT):
                case TRANSITION(OVS_KEY_ATTR_TUN_ID, OVS_KEY_ATTR_IN_PORT):
                        if (nla_get_u32(nla) >= DP_MAX_PORTS)
                                return -EINVAL;
@@ -1196,7 +1213,10 @@ int flow_to_nlattrs(const struct sw_flow_key *swkey, 
struct sk_buff *skb)
        /* This is an imperfect sanity-check that FLOW_BUFSIZE doesn't need
         * to be updated, but will at least raise awareness when new
         * datapath key types are added. */
-       BUILD_BUG_ON(__OVS_KEY_ATTR_MAX != 14);
+       BUILD_BUG_ON(__OVS_KEY_ATTR_MAX != 15);
+
+       if (swkey->priority)
+               NLA_PUT_U32(skb, OVS_KEY_ATTR_PRIORITY, swkey->priority);
 
        if (swkey->eth.tun_id != cpu_to_be64(0))
                NLA_PUT_BE64(skb, OVS_KEY_ATTR_TUN_ID, swkey->eth.tun_id);
diff --git a/datapath/flow.h b/datapath/flow.h
index 484ea62..e7a8c77 100644
--- a/datapath/flow.h
+++ b/datapath/flow.h
@@ -35,6 +35,7 @@ struct sw_flow_actions {
 #define OVS_FRAG_TYPE_MASK INET_ECN_MASK
 
 struct sw_flow_key {
+       u32     priority;               /* Packet QoS priority. */
        struct {
                __be64 tun_id;          /* Encapsulating tunnel ID. */
                u16    in_port;         /* Input switch port (or USHRT_MAX). */
@@ -138,6 +139,7 @@ u64 flow_used_time(unsigned long flow_jiffies);
  *
  *                         struct  pad  nl hdr  total
  *                         ------  ---  ------  -----
+ *  OVS_KEY_ATTR_PRIORITY      4    --     4      8
  *  OVS_KEY_ATTR_TUN_ID        8    --     4     12
  *  OVS_KEY_ATTR_IN_PORT       4    --     4      8
  *  OVS_KEY_ATTR_ETHERNET     12    --     4     16
@@ -147,14 +149,14 @@ u64 flow_used_time(unsigned long flow_jiffies);
  *  OVS_KEY_ATTR_ICMPV6        2     2     4      8
  *  OVS_KEY_ATTR_ND           28    --     4     32
  *  -------------------------------------------------
- *  total                                       132
+ *  total                                      140
  */
-#define FLOW_BUFSIZE 132
+#define FLOW_BUFSIZE 140
 
 int flow_to_nlattrs(const struct sw_flow_key *, struct sk_buff *);
 int flow_from_nlattrs(struct sw_flow_key *swkey, int *key_lenp,
                      const struct nlattr *);
-int flow_metadata_from_nlattrs(u16 *in_port, __be64 *tun_id,
+int flow_metadata_from_nlattrs(u32 *priority, u16 *in_port, __be64 *tun_id,
                               const struct nlattr *);
 
 #define TBL_MIN_BUCKETS                1024
diff --git a/include/linux/openvswitch.h b/include/linux/openvswitch.h
index 087655c..57ce4ef 100644
--- a/include/linux/openvswitch.h
+++ b/include/linux/openvswitch.h
@@ -263,6 +263,7 @@ struct ovs_flow_stats {
 
 enum ovs_key_attr {
        OVS_KEY_ATTR_UNSPEC,
+       OVS_KEY_ATTR_PRIORITY,  /* 32-bit skb->priority */
        OVS_KEY_ATTR_TUN_ID,    /* 64-bit tunnel ID */
        OVS_KEY_ATTR_IN_PORT,   /* 32-bit OVS dp port number */
        OVS_KEY_ATTR_ETHERNET,  /* struct ovs_key_ethernet */
@@ -449,9 +450,6 @@ enum ovs_userspace_attr {
  * header.
  * @OVS_ACTION_ATTR_SET: Replaces the contents of an existing header.
  * The argument takes the same form as %OVS_ACTION_ATTR_PUSH.
- * @OVS_ACTION_ATTR_SET_PRIORITY: Sets skb->priority to 32-bit number passed
- * as argument.
- * @OVS_ACTION_ATTR_POP_PRIORITY: Restore skb->priority to original value.
  * @OVS_ACTION_ATTR_SAMPLE: Probabilitically executes actions, as specified in
  * the nested %OVS_SAMPLE_ATTR_* attributes.
  *
@@ -466,8 +464,6 @@ enum ovs_action_attr {
        OVS_ACTION_ATTR_PUSH,         /* One nested OVS_KEY_ATTR_*. */
        OVS_ACTION_ATTR_POP,          /* u16 OVS_KEY_ATTR_*. */
        OVS_ACTION_ATTR_SET,          /* One nested OVS_KEY_ATTR_*. */
-       OVS_ACTION_ATTR_SET_PRIORITY, /* u32 skb->priority value. */
-       OVS_ACTION_ATTR_POP_PRIORITY, /* No argument. */
        OVS_ACTION_ATTR_SAMPLE,       /* Nested OVS_SAMPLE_ATTR_*. */
        __OVS_ACTION_ATTR_MAX
 };
diff --git a/lib/classifier.c b/lib/classifier.c
index 869029f..0a59e61 100644
--- a/lib/classifier.c
+++ b/lib/classifier.c
@@ -70,6 +70,7 @@ cls_rule_init(const struct flow *flow, const struct 
flow_wildcards *wildcards,
               unsigned int priority, struct cls_rule *rule)
 {
     rule->flow = *flow;
+    rule->flow.priority = 0;
     rule->wc = *wildcards;
     rule->priority = priority;
     cls_rule_zero_wildcarded_fields(rule);
@@ -83,6 +84,7 @@ cls_rule_init_exact(const struct flow *flow,
                     unsigned int priority, struct cls_rule *rule)
 {
     rule->flow = *flow;
+    rule->flow.priority = 0;
     flow_wildcards_init_exact(&rule->wc);
     rule->priority = priority;
 }
@@ -812,6 +814,7 @@ classifier_lookup(const struct classifier *cls, const 
struct flow *flow)
     struct cls_table *table;
     struct cls_rule *best;
 
+    assert(flow->priority == 0);
     best = NULL;
     HMAP_FOR_EACH (table, hmap_node, &cls->tables) {
         struct cls_rule *rule = find_match(table, flow);
@@ -1079,6 +1082,7 @@ insert_rule(struct cls_table *table, struct cls_rule *new)
 {
     struct cls_rule *head;
 
+    assert(new->flow.priority == 0);
     new->hmap_node.hash = flow_hash(&new->flow, 0);
 
     head = find_equal(table, &new->flow, new->hmap_node.hash);
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 1d05dd8..78e6969 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -1239,6 +1239,8 @@ execute_set_action(struct ofpbuf *packet, const struct 
nlattr *a)
     enum ovs_key_attr type = nl_attr_type(a);
     switch (type) {
     case OVS_KEY_ATTR_TUN_ID:
+    case OVS_KEY_ATTR_PRIORITY:
+        /* not implemented */
         break;
 
     case OVS_KEY_ATTR_ETHERNET:
@@ -1319,11 +1321,6 @@ dp_netdev_execute_actions(struct dp_netdev *dp,
             dp_netdev_sample(dp, packet, key, a);
             break;
 
-        case OVS_ACTION_ATTR_SET_PRIORITY:
-        case OVS_ACTION_ATTR_POP_PRIORITY:
-            /* not implemented */
-            break;
-
         case OVS_ACTION_ATTR_UNSPEC:
         case __OVS_ACTION_ATTR_MAX:
             NOT_REACHED();
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 83d56d6..815c321 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -318,8 +318,7 @@ struct dpif_class {
     int (*recv_set_mask)(struct dpif *dpif, int listen_mask);
 
     /* Translates OpenFlow queue ID 'queue_id' (in host byte order) into a
-     * priority value for use in the OVS_ACTION_ATTR_SET_PRIORITY action in
-     * '*priority'. */
+     * priority value for use in the ovs-set-priority action in '*priority'. */
     int (*queue_to_priority)(const struct dpif *dpif, uint32_t queue_id,
                              uint32_t *priority);
 
diff --git a/lib/dpif.c b/lib/dpif.c
index 68a95f6..5962527 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -1129,9 +1129,9 @@ dpif_get_netflow_ids(const struct dpif *dpif,
 }
 
 /* Translates OpenFlow queue ID 'queue_id' (in host byte order) into a priority
- * value for use in the OVS_ACTION_ATTR_SET_PRIORITY action.  On success,
- * returns 0 and stores the priority into '*priority'.  On failure, returns a
- * positive errno value and stores 0 into '*priority'. */
+ * value for use in the ovs-set-priority action.
+ * On success, returns 0 and stores the priority into '*priority'.
+ * On failure, returns a positive errno value and stores 0 into '*priority'. */
 int
 dpif_queue_to_priority(const struct dpif *dpif, uint32_t queue_id,
                        uint32_t *priority)
diff --git a/lib/flow.h b/lib/flow.h
index e9da2ad..eba6eda 100644
--- a/lib/flow.h
+++ b/lib/flow.h
@@ -54,6 +54,7 @@ BUILD_ASSERT_DECL(FLOW_FRAG_LATER == NX_IP_FRAG_LATER);
 
 struct flow {
     ovs_be64 tun_id;            /* Encapsulating tunnel ID. */
+    uint32_t priority;          /* Packet priority for QoS. */
     uint32_t regs[FLOW_N_REGS]; /* Registers. */
     ovs_be32 nw_src;            /* IPv4 source address. */
     ovs_be32 nw_dst;            /* IPv4 destination address. */
@@ -71,18 +72,19 @@ struct flow {
     struct in6_addr ipv6_src;   /* IPv6 source address. */
     struct in6_addr ipv6_dst;   /* IPv6 destination address. */
     struct in6_addr nd_target;  /* IPv6 neighbor discovery (ND) target. */
+    uint32_t reserved;          /* Reserved for 64-bit packing. */
 };
 
 /* Assert that there are FLOW_SIG_SIZE bytes of significant data in "struct
  * flow", followed by FLOW_PAD_SIZE bytes of padding. */
-#define FLOW_SIG_SIZE (100 + FLOW_N_REGS * 4)
-#define FLOW_PAD_SIZE 0
+#define FLOW_SIG_SIZE (104 + FLOW_N_REGS * 4)
+#define FLOW_PAD_SIZE 4
 BUILD_ASSERT_DECL(offsetof(struct flow, nd_target) == FLOW_SIG_SIZE - 16);
 BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->nd_target) == 16);
 BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE);
 
 /* Remember to update FLOW_WC_SEQ when changing 'struct flow'. */
-BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 120 && FLOW_WC_SEQ == 3);
+BUILD_ASSERT_DECL(FLOW_SIG_SIZE == 124 && FLOW_WC_SEQ == 3);
 
 void flow_extract(struct ofpbuf *, ovs_be64 tun_id, uint16_t in_port,
                   struct flow *);
diff --git a/lib/odp-util.c b/lib/odp-util.c
index 33672c8..c83ec55 100644
--- a/lib/odp-util.c
+++ b/lib/odp-util.c
@@ -64,8 +64,6 @@ odp_action_len(uint16_t type)
     case OVS_ACTION_ATTR_PUSH: return -2;
     case OVS_ACTION_ATTR_POP: return 2;
     case OVS_ACTION_ATTR_SET: return -2;
-    case OVS_ACTION_ATTR_SET_PRIORITY: return 4;
-    case OVS_ACTION_ATTR_POP_PRIORITY: return 0;
     case OVS_ACTION_ATTR_SAMPLE: return -2;
 
     case OVS_ACTION_ATTR_UNSPEC:
@@ -205,12 +203,6 @@ format_odp_action(struct ds *ds, const struct nlattr *a)
             ds_put_format(ds, "pop(key%"PRIu16")", nl_attr_get_u16(a));
         }
         break;
-    case OVS_ACTION_ATTR_SET_PRIORITY:
-        ds_put_format(ds, "set_priority(%#"PRIx32")", nl_attr_get_u32(a));
-        break;
-    case OVS_ACTION_ATTR_POP_PRIORITY:
-        ds_put_cstr(ds, "pop_priority");
-        break;
     case OVS_ACTION_ATTR_SAMPLE:
         format_odp_sample_action(ds, a);
         break;
@@ -257,6 +249,7 @@ odp_flow_key_attr_len(uint16_t type)
     }
 
     switch ((enum ovs_key_attr) type) {
+    case OVS_KEY_ATTR_PRIORITY: return sizeof(uint32_t);
     case OVS_KEY_ATTR_TUN_ID: return 8;
     case OVS_KEY_ATTR_IN_PORT: return 4;
     case OVS_KEY_ATTR_ETHERNET: return sizeof(struct ovs_key_ethernet);
@@ -338,6 +331,10 @@ format_odp_key_attr(const struct nlattr *a, struct ds *ds)
     }
 
     switch (nl_attr_type(a)) {
+    case OVS_KEY_ATTR_PRIORITY:
+        ds_put_format(ds, "QoS(priority=%"PRIu32")", nl_attr_get_u32(a));
+        break;
+
     case OVS_KEY_ATTR_TUN_ID:
         ds_put_format(ds, "tun_id(%#"PRIx64")", ntohll(nl_attr_get_be64(a)));
         break;
@@ -528,6 +525,16 @@ parse_odp_key_attr(const char *s, struct ofpbuf *key)
      * type larger than 64 bits. */
 
     {
+        unsigned long long int priority;
+        int n = -1;
+
+        if (sscanf(s, "QoS(priority=%lli)%n", &priority, &n) > 0 && n > 0) {
+            nl_msg_put_u32(key, OVS_KEY_ATTR_PRIORITY, priority);
+            return n;
+        }
+    }
+
+    {
         char tun_id_s[32];
         int n = -1;
 
@@ -824,6 +831,10 @@ odp_flow_key_from_flow(struct ofpbuf *buf, const struct 
flow *flow)
 {
     struct ovs_key_ethernet *eth_key;
 
+    if (flow->priority) {
+        nl_msg_put_u32(buf, OVS_KEY_ATTR_PRIORITY, flow->priority);
+    }
+
     if (flow->tun_id != htonll(0)) {
         nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tun_id);
     }
@@ -991,11 +1002,17 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t 
key_len,
 
 #define TRANSITION(PREV_TYPE, TYPE) (((PREV_TYPE) << 16) | (TYPE))
         switch (TRANSITION(prev_type, type)) {
+        case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_PRIORITY):
+            flow->priority = nl_attr_get_u32(nla);
+            break;
+
         case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_TUN_ID):
+        case TRANSITION(OVS_KEY_ATTR_PRIORITY, OVS_KEY_ATTR_TUN_ID):
             flow->tun_id = nl_attr_get_be64(nla);
             break;
 
         case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_IN_PORT):
+        case TRANSITION(OVS_KEY_ATTR_PRIORITY, OVS_KEY_ATTR_IN_PORT):
         case TRANSITION(OVS_KEY_ATTR_TUN_ID, OVS_KEY_ATTR_IN_PORT):
             if (nl_attr_get_u32(nla) >= UINT16_MAX) {
                 return EINVAL;
@@ -1004,6 +1021,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t 
key_len,
             break;
 
         case TRANSITION(OVS_KEY_ATTR_UNSPEC, OVS_KEY_ATTR_ETHERNET):
+        case TRANSITION(OVS_KEY_ATTR_PRIORITY, OVS_KEY_ATTR_ETHERNET):
         case TRANSITION(OVS_KEY_ATTR_TUN_ID, OVS_KEY_ATTR_ETHERNET):
         case TRANSITION(OVS_KEY_ATTR_IN_PORT, OVS_KEY_ATTR_ETHERNET):
             eth_key = nl_attr_get(nla);
@@ -1137,6 +1155,7 @@ odp_flow_key_to_flow(const struct nlattr *key, size_t 
key_len,
     case OVS_KEY_ATTR_UNSPEC:
         return EINVAL;
 
+    case OVS_KEY_ATTR_PRIORITY:
     case OVS_KEY_ATTR_TUN_ID:
     case OVS_KEY_ATTR_IN_PORT:
         return EINVAL;
diff --git a/lib/odp-util.h b/lib/odp-util.h
index 8c7d4d1..eceeae6 100644
--- a/lib/odp-util.h
+++ b/lib/odp-util.h
@@ -66,6 +66,7 @@ void format_odp_actions(struct ds *, const struct nlattr 
*odp_actions,
  *
  *                         struct  pad  nl hdr  total
  *                         ------  ---  ------  -----
+ *  OVS_KEY_ATTR_PRIORITY      4    --     4      8
  *  OVS_KEY_ATTR_TUN_ID        8    --     4     12
  *  OVS_KEY_ATTR_IN_PORT       4    --     4      8
  *  OVS_KEY_ATTR_ETHERNET     12    --     4     16
@@ -75,14 +76,14 @@ void format_odp_actions(struct ds *, const struct nlattr 
*odp_actions,
  *  OVS_KEY_ATTR_ICMPV6        2     2     4      8
  *  OVS_KEY_ATTR_ND           28    --     4     32
  *  -------------------------------------------------
- *  total                                       132
+ *  total                                       140
  */
-#define ODPUTIL_FLOW_KEY_BYTES 132
+#define ODPUTIL_FLOW_KEY_BYTES 140
 
 /* This is an imperfect sanity-check that ODPUTIL_FLOW_KEY_BYTES doesn't
  * need to be updated, but will at least raise awareness when new OVS
  * datapath key types are added. */
-BUILD_ASSERT_DECL(__OVS_KEY_ATTR_MAX == 14);
+BUILD_ASSERT_DECL(__OVS_KEY_ATTR_MAX == 15);
 
 /* A buffer with sufficient size and alignment to hold an nlattr-formatted flow
  * key.  An array of "struct nlattr" might not, in theory, be sufficiently
diff --git a/lib/ofp-util.c b/lib/ofp-util.c
index 328d0df..5d88d8b 100644
--- a/lib/ofp-util.c
+++ b/lib/ofp-util.c
@@ -144,6 +144,7 @@ ofputil_cls_rule_from_match(const struct ofp_match *match,
     ofputil_wildcard_from_openflow(ofpfw, &rule->wc);
 
     /* Initialize most of rule->flow. */
+    rule->flow.priority = 0;
     rule->flow.nw_src = match->nw_src;
     rule->flow.nw_dst = match->nw_dst;
     rule->flow.in_port = ntohs(match->in_port);
diff --git a/ofproto/ofproto-dpif.c b/ofproto/ofproto-dpif.c
index b53452d..7ef87f1 100644
--- a/ofproto/ofproto-dpif.c
+++ b/ofproto/ofproto-dpif.c
@@ -205,9 +205,8 @@ struct action_xlate_ctx {
  * reason to look at them. */
 
     int recurse;                /* Recursion level, via xlate_table_action. */
-    uint32_t priority;          /* Current flow priority. 0 if none. */
     struct flow base_flow;      /* Flow at the last commit. */
-    uint32_t base_priority;     /* Priority at the last commit. */
+    uint32_t original_priority; /* Priority when packet arrived. */
     uint8_t table_id;           /* OpenFlow table ID where flow was found. */
     uint32_t sflow_n_outputs;   /* Number of output ports. */
     uint16_t sflow_odp_port;    /* Output port for composing sFlow action. */
@@ -3238,6 +3237,7 @@ static struct rule_dpif *
 rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow,
                  uint8_t table_id)
 {
+    struct flow cl_flow;
     struct cls_rule *cls_rule;
     struct classifier *cls;
 
@@ -3245,18 +3245,21 @@ rule_dpif_lookup(struct ofproto_dpif *ofproto, const 
struct flow *flow,
         return NULL;
     }
 
-    cls = &ofproto->up.tables[table_id];
+    cl_flow = *flow;
+
+    /* Priority is ignored in classifier. */
+    cl_flow.priority = 0;
+
     if (flow->tos_frag & FLOW_FRAG_ANY
         && ofproto->up.frag_handling == OFPC_FRAG_NORMAL) {
         /* For OFPC_NORMAL frag_handling, we must pretend that transport ports
          * are unavailable. */
-        struct flow ofpc_normal_flow = *flow;
-        ofpc_normal_flow.tp_src = htons(0);
-        ofpc_normal_flow.tp_dst = htons(0);
-        cls_rule = classifier_lookup(cls, &ofpc_normal_flow);
-    } else {
-        cls_rule = classifier_lookup(cls, flow);
+        cl_flow.tp_src = htons(0);
+        cl_flow.tp_dst = htons(0);
     }
+
+    cls = &ofproto->up.tables[table_id];
+    cls_rule = classifier_lookup(cls, &cl_flow);
     return rule_dpif_cast(rule_from_cls_rule(cls_rule));
 }
 
@@ -3721,19 +3724,17 @@ commit_set_port_action(const struct flow *flow, struct 
flow *base,
 }
 
 static void
-commit_priority_action(struct action_xlate_ctx *ctx)
+commit_set_priority_action(const struct flow *flow, struct flow *base,
+                           struct ofpbuf *odp_actions)
 {
-    if (ctx->base_priority == ctx->priority) {
+    if (base->priority == flow->priority) {
         return;
     }
+    base->priority = flow->priority;
 
-    if (ctx->priority) {
-        nl_msg_put_u32(ctx->odp_actions,
-                        OVS_ACTION_ATTR_SET_PRIORITY, ctx->priority);
-    } else {
-        nl_msg_put_flag(ctx->odp_actions, OVS_ACTION_ATTR_POP_PRIORITY);
-    }
-    ctx->base_priority = ctx->priority;
+    commit_action__(odp_actions, OVS_ACTION_ATTR_SET,
+                    OVS_KEY_ATTR_PRIORITY, &base->priority,
+                    sizeof(uint32_t));
 }
 
 static void
@@ -3748,7 +3749,7 @@ commit_odp_actions(struct action_xlate_ctx *ctx)
     commit_vlan_action(ctx, flow->vlan_tci);
     commit_set_nw_action(flow, base, odp_actions);
     commit_set_port_action(flow, base, odp_actions);
-    commit_priority_action(ctx);
+    commit_set_priority_action(flow, base, odp_actions);
 }
 
 static void
@@ -3957,7 +3958,7 @@ xlate_enqueue_action(struct action_xlate_ctx *ctx,
                      const struct ofp_action_enqueue *oae)
 {
     uint16_t ofp_port, odp_port;
-    uint32_t ctx_priority, priority;
+    uint32_t priority;
     int error;
 
     error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(oae->queue_id),
@@ -3978,10 +3979,8 @@ xlate_enqueue_action(struct action_xlate_ctx *ctx,
     odp_port = ofp_port_to_odp_port(ofp_port);
 
     /* Add datapath actions. */
-    ctx_priority = ctx->priority;
-    ctx->priority = priority;
+    ctx->flow.priority = priority;
     add_output_action(ctx, odp_port);
-    ctx->priority = ctx_priority;
 
     /* Update NetFlow output port. */
     if (ctx->nf_output_iface == NF_OUT_DROP) {
@@ -4006,7 +4005,7 @@ xlate_set_queue_action(struct action_xlate_ctx *ctx,
         return;
     }
 
-    ctx->priority = priority;
+    ctx->flow.priority = priority;
 }
 
 struct xlate_reg_state {
@@ -4200,7 +4199,7 @@ do_xlate_actions(const union ofp_action *in, size_t n_in,
             break;
 
         case OFPUTIL_NXAST_POP_QUEUE:
-            ctx->priority = 0;
+            ctx->flow.priority = ctx->original_priority;
             break;
 
         case OFPUTIL_NXAST_REG_MOVE:
@@ -4295,8 +4294,7 @@ xlate_actions(struct action_xlate_ctx *ctx,
     ctx->has_normal = false;
     ctx->nf_output_iface = NF_OUT_DROP;
     ctx->recurse = 0;
-    ctx->priority = 0;
-    ctx->base_priority = 0;
+    ctx->original_priority = ctx->flow.priority;
     ctx->base_flow = ctx->flow;
     ctx->base_flow.tun_id = 0;
     ctx->table_id = 0;
diff --git a/tests/odp.at b/tests/odp.at
index 65a9fb9..07cdc85 100644
--- a/tests/odp.at
+++ b/tests/odp.at
@@ -33,6 +33,10 @@ 
in_port(1),eth(src=00:01:02:03:04:05,dst=10:11:12:13:14:15),eth_type(0x0806),arp
  sed 's/eth([[^)]]*)/&,vlan(vid=99,pcp=7)/' odp-base.txt
 
  echo
+ echo '# Valid forms with QoS priority.'
+ sed 's/^/QoS(priority=1234),/' odp-base.txt
+
+ echo
  echo '# Valid forms with tun_id and VLAN headers.'
  sed 's/^/tun_id(0xfedcba9876543210),/
 s/eth([[^)]]*)/&,vlan(vid=99,pcp=7)/' odp-base.txt
diff --git a/tests/test-classifier.c b/tests/test-classifier.c
index 0e2b13f..fbc7ab7 100644
--- a/tests/test-classifier.c
+++ b/tests/test-classifier.c
@@ -372,6 +372,7 @@ compare_classifiers(struct classifier *cls, struct tcls 
*tcls)
         flow.nw_proto = nw_proto_values[get_value(&x, N_NW_PROTO_VALUES)];
         flow.tos_frag = tos_frag_values[get_value(&x, N_TOS_FRAG_VALUES)];
 
+        flow.priority = 0;
         cr0 = classifier_lookup(cls, &flow);
         cr1 = tcls_lookup(tcls, &flow);
         assert((cr0 == NULL) == (cr1 == NULL));
-- 
1.7.1

_______________________________________________
dev mailing list
dev@openvswitch.org
http://openvswitch.org/mailman/listinfo/dev

Reply via email to