From eedc0097f475a15297375a2aba39313c0f98f330 Mon Sep 17 00:00:00 2001 From: Justin Pettit Date: Sat, 2 Oct 2010 00:27:23 -0700 Subject: [PATCH] Add Nicira extension for modifying queue without transmitting 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 CC: Keith Amidon --- include/openflow/nicira-ext.h | 23 ++++++++++++++++++++++- lib/ofp-parse.c | 11 +++++++++++ lib/ofp-print.c | 11 +++++++++++ lib/ofp-util.c | 2 ++ ofproto/ofproto.c | 30 ++++++++++++++++++++++++++++++ tests/ovs-ofctl.at | 6 +++++- utilities/ovs-ofctl.8.in | 10 ++++++++++ 7 files changed, 91 insertions(+), 2 deletions(-) diff --git a/include/openflow/nicira-ext.h b/include/openflow/nicira-ext.h index c97478fa..df2488bd 100644 --- a/include/openflow/nicira-ext.h +++ b/include/openflow/nicira-ext.h @@ -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. */ diff --git a/lib/ofp-parse.c b/lib/ofp-parse.c index 069687b1..7a888801 100644 --- a/lib/ofp-parse.c +++ b/lib/ofp-parse.c @@ -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")) { diff --git a/lib/ofp-print.c b/lib/ofp-print.c index 569a70ab..1eaaa27d 100644 --- a/lib/ofp-print.c +++ b/lib/ofp-print.c @@ -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)); diff --git a/lib/ofp-util.c b/lib/ofp-util.c index 5171900a..7a2e17cb 100644 --- a/lib/ofp-util.c +++ b/lib/ofp-util.c @@ -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); diff --git a/ofproto/ofproto.c b/ofproto/ofproto.c index 00cac6e2..3d2989a6 100644 --- a/ofproto/ofproto.c +++ b/ofproto/ofproto.c @@ -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. */ diff --git a/tests/ovs-ofctl.at b/tests/ovs-ofctl.at index 2a0ce2cf..f6a5cd81 100644 --- a/tests/ovs-ofctl.at +++ b/tests/ovs-ofctl.at @@ -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 ]) diff --git a/utilities/ovs-ofctl.8.in b/utilities/ovs-ofctl.8.in index c12b5f12..dbcf3a5f 100644 --- a/utilities/ovs-ofctl.8.in +++ b/utilities/ovs-ofctl.8.in @@ -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 -- 2.30.2