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 c97478faf3bc337d7649aff8cfb97cfdc7425ee5..df2488bd9200caa47d1095ba352230576e6230de 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 069687b15aed0a7e4ed71140b1734c8cc7c4d94f..7a888801e7159043743f2baf244ef4a214e49178 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 569a70aba5a53b72555ea9894147c162e986aa05..1eaaa27d8f757bfd3aabd98a5433f96470d5eab0 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 5171900a77ecc5da665382f5df82b281f1b45d0e..7a2e17cb2706abfcdb7e768f4daa30474802fc27 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 00cac6e20753a29e8aa7fa158545179f2fecd153..3d2989a624a4e067ae67222ab9b1d8e480ac1818 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 2a0ce2cf9dd04a40469778563c8e940676aef38e..f6a5cd81ea70bc0a6384b2430cc7ed5764860bd2 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 c12b5f12589fad2f4cf88839c315a95fdd47d3a7..dbcf3a5f25b8fab4a9a247efe636a8ed3fc17839 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