static void init_actions(struct odp_actions *);
static void free_actions(struct odp_actions *);
-static void ofp_actions_to_odp_actions(uint16_t ofp_in_port,
- const struct ofp_action_header *in_,
- size_t n_in, struct odp_actions *out);
+static void xlate_actions(const union ofp_action *in, size_t n_in,
+ const flow_t *flow, struct ofproto *ofproto,
+ struct odp_actions *out);
#define UNKNOWN_SUPER ((struct rule *)-1)
struct rule {
static void rule_destroy(struct rule *);
static inline size_t rule_size(int n_actions);
static struct rule *rule_from_cls_rule(const struct cls_rule *);
-static void rule_make_actions(const struct rule *, struct odp_actions *);
+static void rule_make_actions(struct ofproto *,
+ const struct rule *, struct odp_actions *);
struct ofconn {
struct list node;
static void send_packet_in_action(struct ofpbuf *, void *ofproto);
static void update_used(struct ofproto *);
static void expire_rule(struct cls_rule *, void *ofproto);
-static void revalidate_subrule(struct cls_rule *, void *ofproto);
+static bool revalidate_subrule(struct ofproto *p, struct rule *subrule);
+static void revalidate_subrule_cb(struct cls_rule *sub_, void *p_);
static void handle_odp_msg(struct ofproto *, struct ofpbuf *);
}
if (p->need_revalidate) {
- classifier_for_each_with_wildcards(&p->cls, 0, revalidate_subrule, p);
+ classifier_for_each_with_wildcards(&p->cls, 0, revalidate_subrule_cb,
+ p);
p->need_revalidate = false;
}
}
struct odp_actions odp_actions;
int error;
- ofp_actions_to_odp_actions(odp_port_to_ofp_port(flow->in_port),
- (const struct ofp_action_header *) actions,
- n_actions, &odp_actions);
+ xlate_actions(actions, n_actions, flow, p, &odp_actions);
error = dpif_execute(&p->dpif, flow->in_port, odp_actions.actions,
odp_actions.n_actions, packet);
free_actions(&odp_actions);
rule_destroy(displaced_rule);
}
- rule_make_actions(rule, &odp_actions);
+ rule_make_actions(p, rule, &odp_actions);
if (packet) {
if (!ofproto_send_packet(p, flow, actions, n_actions, packet)) {
rule->byte_count = packet->size;
}
static void
-rule_make_actions(const struct rule *rule, struct odp_actions *actions)
+rule_make_actions(struct ofproto *p,
+ const struct rule *rule, struct odp_actions *actions)
{
const struct rule *super = rule->super ? rule->super : rule;
assert(!rule->cr.wc.wildcards);
- ofp_actions_to_odp_actions(odp_port_to_ofp_port(rule->cr.flow.in_port),
- (const struct ofp_action_header *) super->actions,
- super->n_actions, actions);
+ xlate_actions(super->actions, super->n_actions, &rule->cr.flow, p,
+ actions);
}
\f
static void
a->controller.arg = oao->max_len ? ntohs(oao->max_len) : UINT32_MAX;
}
-static int
-ofp_to_odp_action_output(struct odp_actions *actions, uint16_t ofp_in_port,
- const struct ofp_action_output *oao)
+struct action_xlate_ctx {
+ /* Input. */
+ const union ofp_action *in; /* OpenFlow actions. */
+ size_t n_in; /* Number of elements in 'in' array. */
+ const flow_t *flow; /* Flow to which these actions correspond. */
+ struct ofproto *ofproto; /* For OFPP_TABLE, NXAST_RESUBMIT only. */
+
+ /* Output. */
+ struct odp_actions *out; /* Datapath actions. */
+};
+
+static void do_xlate_actions(struct action_xlate_ctx *ctx);
+
+static void
+xlate_table_action(const struct action_xlate_ctx *ctx, uint16_t in_port)
+{
+ struct ofproto *p = ctx->ofproto;
+ struct action_xlate_ctx nested_ctx;
+ struct rule *rule;
+ flow_t flow;
+
+ if (!p) {
+ return;
+ }
+
+ flow = *ctx->flow;
+ flow.in_port = in_port;
+
+ rule = rule_from_cls_rule(classifier_lookup(&p->cls, &flow));
+ if (!rule) {
+ return;
+ } else if (rule->super && p->need_revalidate) {
+ /* This might be a subrule that is now invalid. Revalidate it. */
+ if (!revalidate_subrule(p, rule)) {
+ /* The subrule got deleted so we can optimize slightly by only
+ * look through the wildcarded rules. */
+ rule = rule_from_cls_rule(classifier_lookup_wild(&p->cls, &flow));
+ if (!rule) {
+ return;
+ }
+ }
+ }
+ if (rule->super) {
+ rule = rule->super;
+ }
+
+ nested_ctx.in = rule->actions;
+ nested_ctx.n_in = rule->n_actions;
+ nested_ctx.flow = &flow;
+ nested_ctx.ofproto = NULL; /* Prevent recursion. */
+ nested_ctx.out = ctx->out;
+ do_xlate_actions(&nested_ctx);
+}
+
+static void
+xlate_output_action(const struct action_xlate_ctx *ctx,
+ const struct ofp_action_output *oao)
{
+ uint16_t odp_port;
+
switch (ntohs(oao->port)) {
case OFPP_IN_PORT:
- add_output_action(actions, ofp_port_to_odp_port(ofp_in_port));
+ add_output_action(ctx->out, ctx->flow->in_port);
break;
case OFPP_TABLE:
- /* XXX not implemented */
+ xlate_table_action(ctx, ctx->flow->in_port);
break;
case OFPP_NORMAL:
- add_output_group_action(actions, DP_GROUP_FLOOD); /* XXX */
+ add_output_group_action(ctx->out, DP_GROUP_FLOOD); /* XXX */
break;
case OFPP_FLOOD:
- add_output_group_action(actions, DP_GROUP_FLOOD);
+ add_output_group_action(ctx->out, DP_GROUP_FLOOD);
break;
case OFPP_ALL:
- add_output_group_action(actions, DP_GROUP_ALL);
+ add_output_group_action(ctx->out, DP_GROUP_ALL);
break;
case OFPP_CONTROLLER:
- add_controller_action(actions, oao);
+ add_controller_action(ctx->out, oao);
break;
case OFPP_LOCAL:
- add_output_action(actions, ODPP_LOCAL);
+ add_output_action(ctx->out, ODPP_LOCAL);
break;
default:
- if (ntohs(oao->port) != ofp_in_port) {
- add_output_action(actions, ofp_port_to_odp_port(ntohs(oao->port)));
+ odp_port = ofp_port_to_odp_port(ntohs(oao->port));
+ if (odp_port != ctx->flow->in_port) {
+ add_output_action(ctx->out, odp_port);
}
break;
}
- return 0;
}
static void
-ofp_actions_to_odp_actions(uint16_t ofp_in_port,
- const struct ofp_action_header *in_, size_t n_in,
- struct odp_actions *out)
+xlate_nicira_action(const struct action_xlate_ctx *ctx,
+ const struct nx_action_header *nah)
+{
+ const struct nx_action_snat *nas;
+ const struct nx_action_resubmit *nar;
+ int subtype = ntohs(nah->subtype);
+ union odp_action *oa;
+
+ assert(nah->vendor == htonl(NX_VENDOR_ID));
+ switch (subtype) {
+ case NXAST_SNAT:
+ nas = (const struct nx_action_snat *) nah;
+ oa = add_action(ctx->out, ODPAT_SNAT);
+ oa->snat.port = ntohs(nas->port);
+ break;
+
+ case NXAST_RESUBMIT:
+ nar = (const struct nx_action_resubmit *) nah;
+ xlate_table_action(ctx, ofp_port_to_odp_port(ntohs(nar->in_port)));
+ break;
+
+ default:
+ VLOG_DBG_RL(&rl, "unknown Nicira action type %"PRIu16, subtype);
+ break;
+ }
+}
+
+static void
+do_xlate_actions(struct action_xlate_ctx *ctx)
{
- union ofp_action *in = (union ofp_action *) in_;
struct actions_iterator iter;
- const union ofp_action *a;
+ const union ofp_action *ia;
- init_actions(out);
- for (a = actions_first(&iter, in, n_in); a; a = actions_next(&iter)) {
- uint16_t type = ntohs(a->type);
+ for (ia = actions_first(&iter, ctx->in, ctx->n_in); ia;
+ ia = actions_next(&iter))
+ {
+ uint16_t type = ntohs(ia->type);
union odp_action *oa;
switch (type) {
case OFPAT_OUTPUT:
- ofp_to_odp_action_output(out, ofp_in_port, &a->output);
+ xlate_output_action(ctx, &ia->output);
break;
case OFPAT_SET_VLAN_VID:
- oa = add_action(out, ODPAT_SET_VLAN_VID);
- oa->vlan_vid.vlan_vid = a->vlan_vid.vlan_vid;
+ oa = add_action(ctx->out, ODPAT_SET_VLAN_VID);
+ oa->vlan_vid.vlan_vid = ia->vlan_vid.vlan_vid;
break;
case OFPAT_SET_VLAN_PCP:
- oa = add_action(out, ODPAT_SET_VLAN_PCP);
- oa->vlan_pcp.vlan_pcp = a->vlan_pcp.vlan_pcp;
+ oa = add_action(ctx->out, ODPAT_SET_VLAN_PCP);
+ oa->vlan_pcp.vlan_pcp = ia->vlan_pcp.vlan_pcp;
break;
case OFPAT_STRIP_VLAN:
- add_action(out, ODPAT_STRIP_VLAN);
+ add_action(ctx->out, ODPAT_STRIP_VLAN);
break;
case OFPAT_SET_DL_SRC:
- oa = add_action(out, ODPAT_SET_DL_SRC);
+ oa = add_action(ctx->out, ODPAT_SET_DL_SRC);
memcpy(oa->dl_addr.dl_addr,
- ((struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
+ ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
break;
case OFPAT_SET_DL_DST:
- oa = add_action(out, ODPAT_SET_DL_DST);
+ oa = add_action(ctx->out, ODPAT_SET_DL_DST);
memcpy(oa->dl_addr.dl_addr,
- ((struct ofp_action_dl_addr *) a)->dl_addr, ETH_ADDR_LEN);
+ ((struct ofp_action_dl_addr *) ia)->dl_addr, ETH_ADDR_LEN);
break;
case OFPAT_SET_NW_SRC:
- oa = add_action(out, ODPAT_SET_NW_SRC);
- oa->nw_addr.nw_addr = a->nw_addr.nw_addr;
+ oa = add_action(ctx->out, ODPAT_SET_NW_SRC);
+ oa->nw_addr.nw_addr = ia->nw_addr.nw_addr;
break;
case OFPAT_SET_TP_SRC:
- oa = add_action(out, ODPAT_SET_TP_SRC);
- oa->tp_port.tp_port = a->tp_port.tp_port;
+ oa = add_action(ctx->out, ODPAT_SET_TP_SRC);
+ oa->tp_port.tp_port = ia->tp_port.tp_port;
break;
case OFPAT_VENDOR:
- if (a->vendor.vendor == htonl(NX_VENDOR_ID)) {
- const struct nx_action_snat *nas =
- (const struct nx_action_snat *) a;
- if (nas->subtype == htons(NXAST_SNAT)) {
- oa = add_action(out, ODPAT_SNAT);
- oa->snat.port = ntohs(nas->port);
- }
- }
+ xlate_nicira_action(ctx, (const struct nx_action_header *) ia);
break;
default:
}
}
+static void
+xlate_actions(const union ofp_action *in, size_t n_in,
+ const flow_t *flow, struct ofproto *ofproto,
+ struct odp_actions *out)
+{
+ struct action_xlate_ctx ctx;
+ init_actions(out);
+ ctx.in = in;
+ ctx.n_in = n_in;
+ ctx.flow = flow;
+ ctx.ofproto = ofproto;
+ ctx.out = out;
+ do_xlate_actions(&ctx);
+}
+
static int
handle_packet_out(struct ofproto *p, struct ofconn *ofconn,
struct ofp_header *oh)
struct odp_actions actions;
int n_actions;
uint16_t in_port;
+ flow_t flow;
int error;
error = check_ofp_packet_out(oh, &payload, &n_actions);
buffer = NULL;
}
- in_port = ofp_port_to_odp_port(ntohs(opo->in_port));
- ofp_actions_to_odp_actions(ntohs(opo->in_port), opo->actions,
- n_actions, &actions);
- dpif_execute(&p->dpif, in_port, actions.actions, actions.n_actions,
+ flow_extract(&payload, ofp_port_to_odp_port(ntohs(opo->in_port)), &flow);
+ xlate_actions((const union ofp_action *) opo->actions, n_actions, &flow,
+ p, &actions);
+ dpif_execute(&p->dpif, flow.in_port, actions.actions, actions.n_actions,
&payload);
free_actions(&actions);
ofpbuf_delete(buffer);
}
static int
-send_buffered(struct ofproto *p, struct ofconn *ofconn,
- struct ofp_flow_mod *ofm, size_t n_actions,
- int *byte_count)
+send_buffered(struct ofproto *p, struct ofconn *ofconn, uint32_t buffer_id,
+ const struct rule *rule, int *byte_count)
{
struct odp_actions actions;
struct ofpbuf *packet;
uint16_t in_port;
+ flow_t flow;
int error;
- *byte_count = 0;
- if (ofm->buffer_id == htonl(UINT32_MAX)) {
- return 0;
- } else if (!ofconn->pktbuf) {
+ if (!ofconn->pktbuf) {
VLOG_WARN_RL(&rl, "attempt to send buffered packet via connection "
"without buffers");
return ofp_mkerr(OFPET_BAD_REQUEST, OFPBRC_BAD_COOKIE);
}
- error = pktbuf_retrieve(ofconn->pktbuf, ntohl(ofm->buffer_id),
- &packet, &in_port);
+ error = pktbuf_retrieve(ofconn->pktbuf, buffer_id, &packet, &in_port);
if (error) {
return error;
}
- ofp_actions_to_odp_actions(in_port, ofm->actions, n_actions, &actions);
- if (!dpif_execute(&p->dpif, ofp_port_to_odp_port(in_port),
- actions.actions, actions.n_actions, packet)) {
+ flow_extract(packet, in_port, &flow);
+ xlate_actions(rule->actions, rule->n_actions, &flow, p, &actions);
+ error = dpif_execute(&p->dpif, in_port,
+ actions.actions, actions.n_actions, packet);
+ if (!error) {
*byte_count = packet->size;
}
free_actions(&actions);
struct ofp_flow_mod *ofm, size_t n_actions)
{
struct rule *rule, *displaced_rule;
- int byte_count;
int buffer_error = 0;
- buffer_error = send_buffered(p, ofconn, ofm, n_actions, &byte_count);
-
rule = xmalloc(rule_size(n_actions));
cls_rule_from_match(&rule->cr, &ofm->match, ntohs(ofm->priority));
rule->idle_timeout = ntohs(ofm->idle_timeout);
rule->hard_timeout = ntohs(ofm->hard_timeout);
rule->used = rule->created = time_msec();
- rule->packet_count = byte_count > 0;
- rule->byte_count = byte_count;
+ rule->packet_count = 0;
+ rule->byte_count = 0;
rule->tcp_flags = 0;
rule->ip_tos = 0;
rule->super = NULL;
rule->n_actions = n_actions;
memcpy(rule->actions, ofm->actions, n_actions * sizeof *rule->actions);
+ if (ofm->buffer_id != htonl(UINT32_MAX)) {
+ int byte_count = 0;
+ buffer_error = send_buffered(p, ofconn, ntohl(ofm->buffer_id),
+ rule, &byte_count);
+ rule->byte_count += byte_count;
+ rule->packet_count += byte_count > 0;
+ }
+
displaced_rule = rule_from_cls_rule(classifier_insert(&p->cls, &rule->cr));
if (rule->cr.wc.wildcards) {
if (displaced_rule) {
struct odp_flow odp_flow;
subrule->super = rule;
- ofp_actions_to_odp_actions(
- odp_port_to_ofp_port(subrule->cr.flow.in_port),
- (const struct ofp_action_header *) rule->actions,
- rule->n_actions, &actions);
+ xlate_actions(rule->actions, rule->n_actions,
+ &subrule->cr.flow, p, &actions);
odp_flow.key = subrule->cr.flow;
odp_flow.actions = actions.actions;
odp_flow.n_actions = actions.n_actions;
struct odp_flow odp_flow;
struct odp_actions actions;
- ofp_actions_to_odp_actions(ntohs(ofm->match.in_port),
- ofm->actions, n_actions, &actions);
+ xlate_actions((const union ofp_action *) ofm->actions, n_actions,
+ &rule->cr.flow, p, &actions);
odp_flow.key = rule->cr.flow;
odp_flow.actions = actions.actions;
struct odp_flow odp_flow;
struct odp_actions actions;
- ofp_actions_to_odp_actions(rule->cr.flow.in_port,
- ofm->actions, n_actions, &actions);
+ xlate_actions((const union ofp_action *) ofm->actions, n_actions,
+ &rule->cr.flow, p, &actions);
odp_flow.key = rule->cr.flow;
odp_flow.actions = actions.actions;
odp_flow.n_actions = actions.n_actions;
free(subrule);
/* Execute old_sr on packet. */
- rule_make_actions(old_sr, &actions);
+ rule_make_actions(p, old_sr, &actions);
dpif_execute(&p->dpif, msg->port,
actions.actions, actions.n_actions, &payload);
free_actions(&actions);
rule->used = time_msec();
/* Install flow entry into datapath. */
- rule_make_actions(subrule, &actions);
+ rule_make_actions(p, subrule, &actions);
odp_flow.key = flow;
odp_flow.actions = actions.actions;
odp_flow.n_actions = actions.n_actions;
* collision? Oh, it could also indicate that the packet was buffered
* before we processed another packet from the same flow. */
subrule = rule;
- rule_make_actions(subrule, &actions);
+ rule_make_actions(p, subrule, &actions);
}
/* Execute subrule on packet. */
}
\f
static void
-revalidate_subrule(struct cls_rule *sub_, void *p_)
+revalidate_subrule_cb(struct cls_rule *sub_, void *p_)
{
struct rule *sub = rule_from_cls_rule(sub_);
struct ofproto *p = p_;
- struct rule *super;
- if (!sub->super) {
- /* Not a subrule. */
- return;
+ if (sub->super) {
+ revalidate_subrule(p, sub);
}
+}
+
+static bool
+revalidate_subrule(struct ofproto *p, struct rule *sub)
+{
+ const flow_t *flow = &sub->cr.flow;
+ struct rule *super;
- super = rule_from_cls_rule(classifier_lookup_wild(&p->cls, &sub->cr.flow));
+ super = rule_from_cls_rule(classifier_lookup_wild(&p->cls, flow));
if (super != sub->super) {
if (!super) {
struct odp_flow odp_flow;
odp_flow.key = sub->cr.flow;
dpif_flow_del(&p->dpif, &odp_flow);
rule_destroy(sub);
+ return false;
} else {
struct odp_actions actions;
sub->created = super->created;
sub->used = 0;
- rule_make_actions(sub, &actions);
- dpif_flow_set_actions(&p->dpif, &sub->cr.flow, actions.actions,
+ rule_make_actions(p, sub, &actions);
+ dpif_flow_set_actions(&p->dpif, flow, actions.actions,
actions.n_actions);
free_actions(&actions);
}
}
+ return true;
}
static struct ofpbuf *