uint16_t idle_timeout; /* In seconds from time of last use. */
uint16_t hard_timeout; /* In seconds from time of creation. */
bool send_flow_removed; /* Send a flow removed message? */
- long long int used; /* Last-used time (0 if never used). */
+ long long int used; /* Time last used; time created if not used. */
long long int created; /* Creation time. */
uint64_t packet_count; /* Number of packets received. */
uint64_t byte_count; /* Number of bytes received. */
return 0;
}
+/* Adds a flow to the OpenFlow flow table in 'p' that matches 'cls_rule' and
+ * performs the 'n_actions' actions in 'actions'. The new flow will not
+ * timeout.
+ *
+ * If cls_rule->priority is in the range of priorities supported by OpenFlow
+ * (0...65535, inclusive) then the flow will be visible to OpenFlow
+ * controllers; otherwise, it will be hidden.
+ *
+ * The caller retains ownership of 'cls_rule' and 'actions'. */
void
ofproto_add_flow(struct ofproto *p, const struct cls_rule *cls_rule,
- const union ofp_action *actions, size_t n_actions,
- int idle_timeout)
+ const union ofp_action *actions, size_t n_actions)
{
struct rule *rule;
- rule = rule_create(p, NULL, actions, n_actions,
- idle_timeout >= 0 ? idle_timeout : 5 /* XXX */,
- 0, 0, false);
+ rule = rule_create(p, NULL, actions, n_actions, 0, 0, 0, false);
rule->cr = *cls_rule;
rule_insert(p, rule, NULL, 0);
}
= priority;
}
+static void
+xlate_set_dl_tci(struct action_xlate_ctx *ctx)
+{
+ ovs_be16 dl_vlan = ctx->flow.dl_vlan;
+ uint8_t dl_vlan_pcp = ctx->flow.dl_vlan_pcp;
+
+ if (dl_vlan == htons(OFP_VLAN_NONE)) {
+ odp_actions_add(ctx->out, ODPAT_STRIP_VLAN);
+ } else {
+ union odp_action *oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI);
+ oa->dl_tci.tci = htons(ntohs(dl_vlan & htons(VLAN_VID_MASK))
+ | (dl_vlan_pcp << VLAN_PCP_SHIFT)
+ | VLAN_CFI);
+ }
+}
+
+static void
+xlate_reg_move_action(struct action_xlate_ctx *ctx,
+ const struct nx_action_reg_move *narm)
+{
+ ovs_be16 old_vlan = ctx->flow.dl_vlan;
+ uint8_t old_pcp = ctx->flow.dl_vlan_pcp;
+
+ nxm_execute_reg_move(narm, &ctx->flow);
+
+ if (ctx->flow.dl_vlan != old_vlan || ctx->flow.dl_vlan_pcp != old_pcp) {
+ xlate_set_dl_tci(ctx);
+ }
+}
+
static void
xlate_nicira_action(struct action_xlate_ctx *ctx,
const struct nx_action_header *nah)
odp_actions_add(ctx->out, ODPAT_POP_PRIORITY);
break;
+ case NXAST_REG_MOVE:
+ xlate_reg_move_action(ctx, (const struct nx_action_reg_move *) nah);
+ break;
+
+ case NXAST_REG_LOAD:
+ nxm_execute_reg_load((const struct nx_action_reg_load *) nah,
+ &ctx->flow);
+ 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. */
break;
case OFPAT_SET_VLAN_VID:
- oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI);
- oa->dl_tci.tci = ia->vlan_vid.vlan_vid;
- oa->dl_tci.tci |= htons(ctx->flow.dl_vlan_pcp << VLAN_PCP_SHIFT);
ctx->flow.dl_vlan = ia->vlan_vid.vlan_vid;
+ xlate_set_dl_tci(ctx);
break;
case OFPAT_SET_VLAN_PCP:
- oa = odp_actions_add(ctx->out, ODPAT_SET_DL_TCI);
- oa->dl_tci.tci = htons(ia->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT);
- oa->dl_tci.tci |= ctx->flow.dl_vlan;
ctx->flow.dl_vlan_pcp = ia->vlan_pcp.vlan_pcp;
+ xlate_set_dl_tci(ctx);
break;
case OFPAT_STRIP_VLAN:
- odp_actions_add(ctx->out, ODPAT_STRIP_VLAN);
ctx->flow.dl_vlan = htons(OFP_VLAN_NONE);
ctx->flow.dl_vlan_pcp = 0;
+ xlate_set_dl_tci(ctx);
break;
case OFPAT_SET_DL_SRC:
struct ofproto *p = ofconn->ofproto;
struct ofp_packet_out *opo;
struct ofpbuf payload, *buffer;
- struct odp_actions actions;
+ union ofp_action *ofp_actions;
+ struct odp_actions odp_actions;
+ struct ofpbuf request;
struct flow flow;
- int n_actions;
+ size_t n_ofp_actions;
uint16_t in_port;
int error;
+ COVERAGE_INC(ofproto_packet_out);
+
error = reject_slave_controller(ofconn, "OFPT_PACKET_OUT");
if (error) {
return error;
}
- error = check_ofp_packet_out(oh, &payload, &n_actions, p->max_ports);
+ /* Get ofp_packet_out. */
+ request.data = oh;
+ request.size = ntohs(oh->length);
+ opo = ofpbuf_try_pull(&request, offsetof(struct ofp_packet_out, actions));
+ if (!opo) {
+ return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
+ }
+
+ /* Get actions. */
+ error = ofputil_pull_actions(&request, ntohs(opo->actions_len),
+ &ofp_actions, &n_ofp_actions);
if (error) {
return error;
}
- opo = (struct ofp_packet_out *) oh;
- COVERAGE_INC(ofproto_packet_out);
+ /* Get payload. */
if (opo->buffer_id != htonl(UINT32_MAX)) {
error = pktbuf_retrieve(ofconn->pktbuf, ntohl(opo->buffer_id),
&buffer, &in_port);
}
payload = *buffer;
} else {
+ payload = request;
buffer = NULL;
}
- flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow);
- error = xlate_actions((const union ofp_action *) opo->actions, n_actions,
- &flow, p, &payload, &actions, NULL, NULL, NULL);
+ /* Extract flow, check actions. */
+ flow_extract(&payload, 0, ofp_port_to_odp_port(ntohs(opo->in_port)),
+ &flow);
+ error = validate_actions(ofp_actions, n_ofp_actions, &flow, p->max_ports);
+ if (error) {
+ goto exit;
+ }
+
+ /* Send. */
+ error = xlate_actions(ofp_actions, n_ofp_actions, &flow, p, &payload,
+ &odp_actions, NULL, NULL, NULL);
if (!error) {
- dpif_execute(p->dpif, actions.actions, actions.n_actions, &payload);
+ dpif_execute(p->dpif, odp_actions.actions, odp_actions.n_actions,
+ &payload);
}
- ofpbuf_delete(buffer);
- return error;
+exit:
+ ofpbuf_delete(buffer);
+ return 0;
}
static void
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_VENDOR);
}
- if (ntohs(nsm->header.length) < sizeof(struct nicira_stats_msg)) {
+ if (ntohs(osr->header.length) < sizeof(struct nicira_stats_msg)) {
VLOG_WARN_RL(&rl, "truncated Nicira stats request");
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_LEN);
}
return error;
}
- error = validate_actions(fm->actions, fm->n_actions, p->max_ports);
+ error = validate_actions(fm->actions, fm->n_actions,
+ &fm->cr.flow, p->max_ports);
if (error) {
return error;
}
rule->super = super;
rule->hard_timeout = super->hard_timeout;
rule->idle_timeout = super->idle_timeout;
- rule->created = super->created;
- rule->used = 0;
+ rule->created = rule->used = super->created;
}
}