Add Nicira extension for modifying queue without transmitting
authorJustin Pettit <jpettit@nicira.com>
Sat, 2 Oct 2010 07:27:23 +0000 (00:27 -0700)
committerJustin Pettit <jpettit@nicira.com>
Sun, 3 Oct 2010 01:36:10 +0000 (18:36 -0700)
The OpenFlow OFPAT_ENQUEUE action sets a queue id and outputs the packet
in one shot.  There are times in which the queue should be set, but the
output port is not yet known.  This commit adds the NXAST_SET_QUEUE and
NXAST_POP_QUEUE Nicira extension actions to modify the queue
configuration without requiring a port argument.

CC: Jeremy Stribling <strib@nicira.com>
CC: Keith Amidon <keith@nicira.com>
include/openflow/nicira-ext.h
lib/ofp-parse.c
lib/ofp-print.c
lib/ofp-util.c
ofproto/ofproto.c
tests/ovs-ofctl.at
utilities/ovs-ofctl.8.in

index c97478f..df2488b 100644 (file)
@@ -142,7 +142,17 @@ enum nx_action_subtype {
      * This is useful because OpenFlow does not provide a way to match on the
      * Ethernet addresses inside ARP packets, so there is no other way to drop
      * spoofed ARPs other than sending every ARP packet to a controller. */
-    NXAST_DROP_SPOOFED_ARP
+    NXAST_DROP_SPOOFED_ARP,
+
+    /* Set the queue that should be used when packets are output.  This
+     * is similar to the OpenFlow OFPAT_ENQUEUE action, but does not
+     * take the output port as an argument.  This allows the queue
+     * to be defined before the port is known. */
+    NXAST_SET_QUEUE,
+
+    /* Restore the queue to the value it was before any NXAST_SET_QUEUE
+     * actions were used. */
+    NXAST_POP_QUEUE
 };
 
 /* Action structure for NXAST_RESUBMIT. */
@@ -167,6 +177,17 @@ struct nx_action_set_tunnel {
 };
 OFP_ASSERT(sizeof(struct nx_action_set_tunnel) == 16);
 
+/* Action structure for NXAST_SET_QUEUE. */
+struct nx_action_set_queue {
+    uint16_t type;                  /* OFPAT_VENDOR. */
+    uint16_t len;                   /* Length is 16. */
+    uint32_t vendor;                /* NX_VENDOR_ID. */
+    uint16_t subtype;               /* NXAST_SET_QUEUE. */
+    uint8_t pad[2];
+    uint32_t queue_id;              /* Where to enqueue packets. */
+};
+OFP_ASSERT(sizeof(struct nx_action_set_queue) == 16);
+
 /* Header for Nicira-defined actions. */
 struct nx_action_header {
     uint16_t type;                  /* OFPAT_VENDOR. */
index 069687b..7a88880 100644 (file)
@@ -267,6 +267,17 @@ str_to_action(char *str, struct ofpbuf *b)
             nah = put_action(b, sizeof *nah, OFPAT_VENDOR);
             nah->vendor = htonl(NX_VENDOR_ID);
             nah->subtype = htons(NXAST_DROP_SPOOFED_ARP);
+        } else if (!strcasecmp(act, "set_queue")) {
+            struct nx_action_set_queue *nasq;
+            nasq = put_action(b, sizeof *nasq, OFPAT_VENDOR);
+            nasq->vendor = htonl(NX_VENDOR_ID);
+            nasq->subtype = htons(NXAST_SET_QUEUE);
+            nasq->queue_id = htonl(str_to_u32(arg));
+        } else if (!strcasecmp(act, "pop_queue")) {
+            struct nx_action_header *nah;
+            nah = put_action(b, sizeof *nah, OFPAT_VENDOR);
+            nah->vendor = htonl(NX_VENDOR_ID);
+            nah->subtype = htons(NXAST_POP_QUEUE);
         } else if (!strcasecmp(act, "output")) {
             put_output_action(b, str_to_u32(arg));
         } else if (!strcasecmp(act, "enqueue")) {
index 569a70a..1eaaa27 100644 (file)
@@ -205,6 +205,17 @@ ofp_print_nx_action(struct ds *string, const struct nx_action_header *nah)
         ds_put_cstr(string, "drop_spoofed_arp");
         break;
 
+    case NXAST_SET_QUEUE: {
+        const struct nx_action_set_queue *nasq =
+                                            (struct nx_action_set_queue *)nah;
+        ds_put_format(string, "set_queue:%u", ntohl(nasq->queue_id));
+        break;
+    }
+
+    case NXAST_POP_QUEUE:
+        ds_put_cstr(string, "pop_queue");
+        break;
+
     default:
         ds_put_format(string, "***unknown Nicira action:%d***",
                       ntohs(nah->subtype));
index 5171900..7a2e17c 100644 (file)
@@ -565,6 +565,8 @@ check_nicira_action(const union ofp_action *a, unsigned int len)
     case NXAST_RESUBMIT:
     case NXAST_SET_TUNNEL:
     case NXAST_DROP_SPOOFED_ARP:
+    case NXAST_SET_QUEUE:
+    case NXAST_POP_QUEUE:
         return check_action_exact_len(a, len, 16);
     default:
         return ofp_mkerr(OFPET_BAD_ACTION, OFPBAC_BAD_VENDOR_TYPE);
index 00cac6e..3d2989a 100644 (file)
@@ -2661,12 +2661,33 @@ xlate_enqueue_action(struct action_xlate_ctx *ctx,
     }
 }
 
+static void
+xlate_set_queue_action(struct action_xlate_ctx *ctx,
+                       const struct nx_action_set_queue *nasq)
+{
+    uint32_t priority;
+    int error;
+
+    error = dpif_queue_to_priority(ctx->ofproto->dpif, ntohl(nasq->queue_id),
+                                   &priority);
+    if (error) {
+        /* Couldn't translate queue to a priority, so ignore.  A warning
+         * has already been logged. */
+        return;
+    }
+
+    remove_pop_action(ctx);
+    odp_actions_add(ctx->out, ODPAT_SET_PRIORITY)->priority.priority
+        = priority;
+}
+
 static void
 xlate_nicira_action(struct action_xlate_ctx *ctx,
                     const struct nx_action_header *nah)
 {
     const struct nx_action_resubmit *nar;
     const struct nx_action_set_tunnel *nast;
+    const struct nx_action_set_queue *nasq;
     union odp_action *oa;
     int subtype = ntohs(nah->subtype);
 
@@ -2689,6 +2710,15 @@ xlate_nicira_action(struct action_xlate_ctx *ctx,
         }
         break;
 
+    case NXAST_SET_QUEUE:
+        nasq = (const struct nx_action_set_queue *) nah;
+        xlate_set_queue_action(ctx, nasq);
+        break;
+
+    case NXAST_POP_QUEUE:
+        odp_actions_add(ctx->out, ODPAT_POP_PRIORITY);
+        break;
+
     /* If you add a new action here that modifies flow data, don't forget to
      * update the flow key in ctx->flow at the same time. */
 
index 2a0ce2c..f6a5cd8 100644 (file)
@@ -5,8 +5,10 @@ AT_DATA([flows.txt], [
 # comment
 tcp,tp_src=123,actions=flood
 in_port=LOCAL dl_vlan=9 dl_src=00:0A:E4:25:6B:B0 actions=drop
-arp,nw_src=192.168.0.1,actions=drop_spoofed_arp,NORMAL
+arp,nw_src=192.168.0.1 actions=drop_spoofed_arp,NORMAL
 udp dl_vlan_pcp=7 idle_timeout=5 actions=strip_vlan output:0
+tcp,nw_src=192.168.0.3,tp_dst=80 actions=set_queue:37,output:1
+udp,nw_src=192.168.0.3,tp_dst=53 actions=pop_queue,output:1
 cookie=0x123456789abcdef hard_timeout=10 priority=60000 actions=controller
 actions=drop
 ])
@@ -16,6 +18,8 @@ flow_mod: tcp,tp_src=123, ADD: actions=FLOOD
 flow_mod: in_port=65534,dl_vlan=9,dl_src=00:0a:e4:25:6b:b0, ADD: actions=drop
 flow_mod: arp,nw_src=192.168.0.1, ADD: actions=drop_spoofed_arp,NORMAL
 flow_mod: udp,dl_vlan_pcp=7, ADD: idle:5 actions=strip_vlan,output:0
+flow_mod: tcp,nw_src=192.168.0.3,tp_dst=80, ADD: actions=set_queue:37,output:1
+flow_mod: udp,nw_src=192.168.0.3,tp_dst=53, ADD: actions=pop_queue,output:1
 flow_mod: ADD: cookie:0x123456789abcdef hard:10 pri:60000 actions=CONTROLLER:65535
 flow_mod: ADD: actions=drop
 ])
index c12b5f1..dbcf3a5 100644 (file)
@@ -469,6 +469,16 @@ Ethernet header.
 This is useful because OpenFlow does not provide a way to match on the
 Ethernet addresses inside ARP packets, so there is no other way to
 drop spoofed ARPs other than sending every ARP packet to a controller.
+.
+.IP \fBset_queue\fB:\fIqueue\fR
+Sets the queue that should be used to \fIqueue\fR when packets are
+output.  The number of supported queues depends on the switch; some
+OpenFlow implementations do not support queuing at all.
+.
+.IP \fBpop_queue\fR
+Restores the queue to the value it was before any \fBset_queue\fR
+actions were applied.
+.
 .RE
 .
 .IP