* 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. */
};
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. */
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")) {
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));
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);
}
}
+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);
}
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. */
# 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
])
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
])
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