/* Send the packet and credit it to the rule. */
if (packet) {
flow_t flow;
- flow_extract(packet, in_port, &flow);
+ flow_extract(packet, 0, in_port, &flow);
wx_rule_execute(wx, rule, packet, &flow);
}
rule->wr.idle_timeout,
rule->wr.hard_timeout);
COVERAGE_INC(wx_subrule_create);
- cls_rule_from_flow(&subrule->wr.cr, flow);
+ cls_rule_from_flow(flow, &subrule->wr.cr);
classifier_insert_exact(&wx->cls, &subrule->wr.cr);
return subrule;
const struct ofp_action_output *oao)
{
union xflow_action *a = xflow_actions_add(actions, XFLOWAT_CONTROLLER);
- a->controller.arg = oao->max_len ? ntohs(oao->max_len) : UINT32_MAX;
+ a->controller.arg = ntohs(oao->max_len);
}
struct wx_xlate_ctx {
/* Input. */
- const flow_t *flow; /* Flow to which these actions correspond. */
+ flow_t flow; /* Flow to which these actions correspond. */
int recurse; /* Recursion level, via xlate_table_action. */
struct wx *wx;
const struct ofpbuf *packet; /* The packet corresponding to 'flow', or a
xlate_table_action(struct wx_xlate_ctx *ctx, uint16_t in_port)
{
if (!ctx->recurse) {
+ uint16_t old_in_port;
struct wx_rule *rule;
- flow_t flow;
- flow = *ctx->flow;
- flow.in_port = in_port;
+ /* Look up a flow with 'in_port' as the input port. Then restore the
+ * original input port (otherwise OFPP_NORMAL and OFPP_IN_PORT will
+ * have surprising behavior). */
+ old_in_port = ctx->flow.in_port;
+ ctx->flow.in_port = in_port;
+ rule = wx_rule_lookup_valid(ctx->wx, &ctx->flow);
+ ctx->flow.in_port = old_in_port;
- rule = wx_rule_lookup_valid(ctx->wx, &flow);
if (rule) {
if (rule->super) {
rule = rule->super;
switch (ntohs(oao->port)) {
case OFPP_IN_PORT:
- add_output_action(ctx, ctx->flow->in_port);
+ add_output_action(ctx, ctx->flow.in_port);
break;
case OFPP_TABLE:
- xlate_table_action(ctx, ctx->flow->in_port);
+ xlate_table_action(ctx, ctx->flow.in_port);
break;
case OFPP_NORMAL:
#if 0
break;
default:
xflow_port = ofp_port_to_xflow_port(ntohs(oao->port));
- if (xflow_port != ctx->flow->in_port) {
+ if (xflow_port != ctx->flow.in_port) {
add_output_action(ctx, xflow_port);
}
break;
const struct nx_action_header *nah)
{
const struct nx_action_resubmit *nar;
+ const struct nx_action_set_tunnel *nast;
+ union xflow_action *oa;
int subtype = ntohs(nah->subtype);
assert(nah->vendor == htonl(NX_VENDOR_ID));
xlate_table_action(ctx, ofp_port_to_xflow_port(ntohs(nar->in_port)));
break;
+ case NXAST_SET_TUNNEL:
+ nast = (const struct nx_action_set_tunnel *) nah;
+ oa = xflow_actions_add(ctx->out, XFLOWAT_SET_TUNNEL);
+ ctx->flow.tun_id = oa->tunnel.tun_id = nast->tun_id;
+ break;
+
+ /* If you add a new action here that modifies flow data, don't forget to
+ * update the flow key in ctx->flow in the same key. */
+
default:
VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, subtype);
break;
const union ofp_action *ia;
const struct wdp_port *port;
- port = port_array_get(&ctx->wx->ports, ctx->flow->in_port);
+ port = port_array_get(&ctx->wx->ports, ctx->flow.in_port);
if (port && port->opp.config & (OFPPC_NO_RECV | OFPPC_NO_RECV_STP) &&
- port->opp.config & (eth_addr_equals(ctx->flow->dl_dst, stp_eth_addr)
+ port->opp.config & (eth_addr_equals(ctx->flow.dl_dst, stp_eth_addr)
? OFPPC_NO_RECV_STP : OFPPC_NO_RECV)) {
/* Drop this flow. */
return;
oa = xflow_actions_add(ctx->out, XFLOWAT_SET_DL_TCI);
oa->dl_tci.tci = ia->vlan_vid.vlan_vid & htons(VLAN_VID_MASK);
oa->dl_tci.mask = htons(VLAN_VID_MASK);
+ ctx->flow.dl_vlan = ia->vlan_vid.vlan_vid;
break;
case OFPAT_SET_VLAN_PCP:
oa->dl_tci.tci = htons((ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT)
& VLAN_PCP_MASK);
oa->dl_tci.mask = htons(VLAN_PCP_MASK);
+
+ if (ctx->flow.dl_vlan == htons(OFP_VLAN_NONE)) {
+ ctx->flow.dl_vlan = htons(0);
+ }
+ ctx->flow.dl_vlan_pcp = ia->vlan_pcp.vlan_pcp;
break;
case OFPAT_STRIP_VLAN:
xflow_actions_add(ctx->out, XFLOWAT_STRIP_VLAN);
+ ctx->flow.dl_vlan = htons(OFP_VLAN_NONE);
+ ctx->flow.dl_vlan_pcp = 0;
break;
case OFPAT_SET_DL_SRC:
oa = xflow_actions_add(ctx->out, XFLOWAT_SET_DL_SRC);
memcpy(oa->dl_addr.dl_addr,
((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
+ memcpy(ctx->flow.dl_src,
+ ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
break;
case OFPAT_SET_DL_DST:
oa = xflow_actions_add(ctx->out, XFLOWAT_SET_DL_DST);
memcpy(oa->dl_addr.dl_addr,
((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
+ memcpy(ctx->flow.dl_dst,
+ ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
break;
case OFPAT_SET_NW_SRC:
oa = xflow_actions_add(ctx->out, XFLOWAT_SET_NW_SRC);
- oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
+ ctx->flow.nw_src = oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
break;
case OFPAT_SET_NW_DST:
oa = xflow_actions_add(ctx->out, XFLOWAT_SET_NW_DST);
- oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
+ ctx->flow.nw_dst = oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
break;
case OFPAT_SET_NW_TOS:
oa = xflow_actions_add(ctx->out, XFLOWAT_SET_NW_TOS);
- oa->nw_tos.nw_tos = ia->nw_tos.nw_tos;
+ ctx->flow.nw_tos = oa->nw_tos.nw_tos = ia->nw_tos.nw_tos;
break;
case OFPAT_SET_TP_SRC:
oa = xflow_actions_add(ctx->out, XFLOWAT_SET_TP_SRC);
- oa->tp_port.tp_port = ia->tp_port.tp_port;
+ ctx->flow.tp_src = oa->tp_port.tp_port = ia->tp_port.tp_port;
break;
case OFPAT_SET_TP_DST:
oa = xflow_actions_add(ctx->out, XFLOWAT_SET_TP_DST);
- oa->tp_port.tp_port = ia->tp_port.tp_port;
+ ctx->flow.tp_dst = oa->tp_port.tp_port = ia->tp_port.tp_port;
break;
case OFPAT_VENDOR:
struct wx_xlate_ctx ctx;
COVERAGE_INC(wx_ofp2xflow);
xflow_actions_init(out);
- ctx.flow = flow;
+ ctx.flow = *flow;
ctx.recurse = 0;
ctx.wx = wx;
ctx.packet = packet;
if (!error) {
struct wx *wx;
- wx = xmalloc(sizeof *wx);
+ wx = xzalloc(sizeof *wx);
list_push_back(&all_wx, &wx->list_node);
wdp_init(&wx->wdp, wdp_class, name, 0, 0);
wx->xfif = xfif;
rule = wx_rule_create(NULL, put->actions, put->n_actions,
put->idle_timeout, put->hard_timeout);
- cls_rule_from_flow(&rule->wr.cr, put->flow);
+ cls_rule_from_flow(put->flow, &rule->wr.cr);
wx_rule_insert(wx, rule, NULL, 0);
if (old_stats) {
flow_t flow;
int error;
- flow_extract((struct ofpbuf *) packet, in_port, &flow);
+ flow_extract((struct ofpbuf *) packet, 0, in_port, &flow);
error = wx_xlate_actions(wx, actions, n_actions, &flow, packet,
&xflow_actions, NULL);
if (error) {
{
packet->in_port = xflow_port_to_ofp_port(msg->port);
packet->send_len = 0;
+ packet->tun_id = 0;
switch (msg->type) {
case _XFLOWL_MISS_NR:
packet->channel = WDP_CHAN_MISS;
packet->payload = payload;
+ packet->tun_id = msg->arg;
return 0;
case _XFLOWL_ACTION_NR:
struct wx_rule *rule;
flow_t flow;
- flow_extract(payload, xflow_port_to_ofp_port(msg->port), &flow);
+ flow_extract(payload, 0, xflow_port_to_ofp_port(msg->port), &flow);
if (wx_is_local_dhcp_reply(wx, &flow, payload)) {
union xflow_action action;