static void flow_push_stats(struct rule_dpif *, const struct flow *,
const struct dpif_flow_stats *);
static tag_type rule_calculate_tag(const struct flow *,
- const struct flow_wildcards *,
- uint32_t basis);
+ const struct minimask *, uint32_t basis);
static void rule_invalidate(const struct rule_dpif *);
#define MAX_MIRRORS 32
struct hmap_node all_ofproto_dpifs_node; /* In 'all_ofproto_dpifs'. */
struct ofproto up;
struct dpif *dpif;
- int max_ports;
/* Special OpenFlow rules. */
struct rule_dpif *miss_rule; /* Sends flow table misses to controller. */
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
const char *name = ofproto->up.name;
+ int max_ports;
int error;
int i;
return error;
}
- ofproto->max_ports = dpif_get_max_ports(ofproto->dpif);
+ max_ports = dpif_get_max_ports(ofproto->dpif);
+ ofproto_init_max_ports(ofproto_, MIN(max_ports, OFPP_MAX));
+
ofproto->n_matches = 0;
dpif_flow_flush(ofproto->dpif);
struct ofputil_flow_mod fm;
int error;
- cls_rule_init_catchall(&fm.cr, 0);
- cls_rule_set_reg(&fm.cr, 0, id);
+ match_init_catchall(&fm.match);
+ fm.priority = 0;
+ match_set_reg(&fm.match, 0, id);
fm.new_cookie = htonll(0);
fm.cookie = htonll(0);
fm.cookie_mask = htonll(0);
return error;
}
- *rulep = rule_dpif_lookup__(ofproto, &fm.cr.flow, TBL_INTERNAL);
+ *rulep = rule_dpif_lookup__(ofproto, &fm.match.flow, TBL_INTERNAL);
assert(*rulep != NULL);
return 0;
}
static void
-get_tables(struct ofproto *ofproto_, struct ofp10_table_stats *ots)
+get_tables(struct ofproto *ofproto_, struct ofp12_table_stats *ots)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct dpif_dp_stats s;
strcpy(ots->name, "classifier");
dpif_get_dp_stats(ofproto->dpif, &s);
- put_32aligned_be64(&ots->lookup_count, htonll(s.n_hit + s.n_missed));
- put_32aligned_be64(&ots->matched_count,
- htonll(s.n_hit + ofproto->n_matches));
+ ots->lookup_count = htonll(s.n_hit + s.n_missed);
+ ots->matched_count = htonll(s.n_hit + ofproto->n_matches);
}
static struct ofport *
for (upcall = upcalls; upcall < &upcalls[n_upcalls]; upcall++) {
struct flow_miss *miss = &misses[n_misses];
struct flow_miss *existing_miss;
+ struct flow flow;
uint32_t hash;
/* Obtain metadata and check userspace/kernel agreement on flow match,
* then set 'flow''s header pointers. */
miss->key_fitness = ofproto_dpif_extract_flow_key(
ofproto, upcall->key, upcall->key_len,
- &miss->flow, &miss->initial_tci, upcall->packet);
+ &flow, &miss->initial_tci, upcall->packet);
if (miss->key_fitness == ODP_FIT_ERROR) {
continue;
}
- flow_extract(upcall->packet, miss->flow.skb_priority,
- miss->flow.tun_id, miss->flow.in_port, &miss->flow);
+ flow_extract(upcall->packet, flow.skb_priority,
+ &flow.tunnel, flow.in_port, &miss->flow);
/* Add other packets to a to-do list. */
hash = flow_hash(&miss->flow, 0);
struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
struct rule_dpif *victim;
uint8_t table_id;
- enum ofperr error;
-
- error = ofpacts_check(rule->up.ofpacts, rule->up.ofpacts_len,
- &rule->up.cr.flow, ofproto->max_ports);
- if (error) {
- return error;
- }
rule->packet_count = 0;
rule->byte_count = 0;
}
table_id = rule->up.table_id;
- rule->tag = (victim ? victim->tag
- : table_id == 0 ? 0
- : rule_calculate_tag(&rule->up.cr.flow, &rule->up.cr.wc,
- ofproto->tables[table_id].basis));
+ if (victim) {
+ rule->tag = victim->tag;
+ } else if (table_id == 0) {
+ rule->tag = 0;
+ } else {
+ struct flow flow;
+
+ miniflow_expand(&rule->up.cr.match.flow, &flow);
+ rule->tag = rule_calculate_tag(&flow, &rule->up.cr.match.mask,
+ ofproto->tables[table_id].basis);
+ }
complete_operation(rule);
return 0;
rule_modify_actions(struct rule *rule_)
{
struct rule_dpif *rule = rule_dpif_cast(rule_);
- struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
- enum ofperr error;
-
- error = ofpacts_check(rule->up.ofpacts, rule->up.ofpacts_len,
- &rule->up.cr.flow, ofproto->max_ports);
- if (error) {
- ofoperation_complete(rule->up.pending, error);
- return;
- }
complete_operation(rule);
}
struct flow flow;
int error;
- flow_extract(packet, 0, 0, 0, &flow);
+ flow_extract(packet, 0, NULL, 0, &flow);
odp_port = vsp_realdev_to_vlandev(ofproto, ofport->odp_port,
flow.vlan_tci);
if (odp_port != ofport->odp_port) {
if (ofport) {
struct priority_to_dscp *pdscp;
- if (ofport->up.pp.config & OFPUTIL_PC_NO_FWD
- || (check_stp && !stp_forward_in_state(ofport->stp_state))) {
+ if (ofport->up.pp.config & OFPUTIL_PC_NO_FWD) {
+ xlate_report(ctx, "OFPPC_NO_FWD set, skipping output");
+ return;
+ } else if (check_stp && !stp_forward_in_state(ofport->stp_state)) {
+ xlate_report(ctx, "STP not in forwarding state, skipping output");
return;
}
ctx->tags |= (rule && rule->tag
? rule->tag
: rule_calculate_tag(&ctx->flow,
- &table->other_table->wc,
+ &table->other_table->mask,
table->basis));
}
}
default:
if (port != ctx->flow.in_port) {
compose_output_action(ctx, port);
+ } else {
+ xlate_report(ctx, "skipping output to input port");
}
break;
}
}
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
struct ofpact_controller *controller;
+ const struct ofpact_metadata *metadata;
if (ctx->exit) {
break;
ctx->flow.vlan_tci = htons(0);
break;
+ case OFPACT_PUSH_VLAN:
+ /* TODO:XXX 802.1AD(QinQ) */
+ ctx->flow.vlan_tci = htons(VLAN_CFI);
+ break;
+
case OFPACT_SET_ETH_SRC:
memcpy(ctx->flow.dl_src, ofpact_get_SET_ETH_SRC(a)->mac,
ETH_ADDR_LEN);
break;
case OFPACT_SET_TUNNEL:
- ctx->flow.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id);
+ ctx->flow.tunnel.tun_id = htonll(ofpact_get_SET_TUNNEL(a)->tun_id);
break;
case OFPACT_SET_QUEUE:
ctx->has_fin_timeout = true;
xlate_fin_timeout(ctx, ofpact_get_FIN_TIMEOUT(a));
break;
+
+ case OFPACT_CLEAR_ACTIONS:
+ /* TODO:XXX
+ * Nothing to do because writa-actions is not supported for now.
+ * When writa-actions is supported, clear-actions also must
+ * be supported at the same time.
+ */
+ break;
+
+ case OFPACT_WRITE_METADATA:
+ metadata = ofpact_get_WRITE_METADATA(a);
+ ctx->flow.metadata &= ~metadata->mask;
+ ctx->flow.metadata |= metadata->metadata & metadata->mask;
+ break;
+
+ case OFPACT_GOTO_TABLE: {
+ /* TODO:XXX remove recursion */
+ /* It is assumed that goto-table is last action */
+ struct ofpact_goto_table *ogt = ofpact_get_GOTO_TABLE(a);
+ assert(ctx->table_id < ogt->table_id);
+ xlate_table_action(ctx, ctx->flow.in_port, ogt->table_id, true);
+ break;
+ }
}
}
ctx->ofproto = ofproto;
ctx->flow = *flow;
ctx->base_flow = ctx->flow;
- ctx->base_flow.tun_id = 0;
+ memset(&ctx->base_flow.tunnel, 0, sizeof ctx->base_flow.tunnel);
ctx->base_flow.vlan_tci = initial_tci;
ctx->rule = rule;
ctx->packet = packet;
m = ofproto->mirrors[mirror_mask_ffs(mirrors) - 1];
if (!vlan_is_mirrored(m, vlan)) {
- mirrors &= mirrors - 1;
+ mirrors = zero_rightmost_1bit(mirrors);
continue;
}
return;
}
- for (; mirrors; mirrors &= mirrors - 1) {
+ for (; mirrors; mirrors = zero_rightmost_1bit(mirrors)) {
struct ofmirror *m;
m = ofproto->mirrors[mirror_mask_ffs(mirrors) - 1];
* a few more, but not all of the facets or even all of the facets that
* resubmit to the table modified by MAC learning). */
-/* Calculates the tag to use for 'flow' and wildcards 'wc' when it is inserted
+/* Calculates the tag to use for 'flow' and mask 'mask' when it is inserted
* into an OpenFlow table with the given 'basis'. */
static tag_type
-rule_calculate_tag(const struct flow *flow, const struct flow_wildcards *wc,
+rule_calculate_tag(const struct flow *flow, const struct minimask *mask,
uint32_t secret)
{
- if (flow_wildcards_is_catchall(wc)) {
+ if (minimask_is_catchall(mask)) {
return 0;
} else {
- struct flow tag_flow = *flow;
- flow_zero_wildcards(&tag_flow, wc);
- return tag_create_deterministic(flow_hash(&tag_flow, secret));
+ uint32_t hash = flow_hash_in_minimask(flow, mask, secret);
+ return tag_create_deterministic(hash);
}
}
const struct ofpact *ofpacts, size_t ofpacts_len)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- enum ofperr error;
-
- if (flow->in_port >= ofproto->max_ports && flow->in_port < OFPP_MAX) {
- return OFPERR_NXBRC_BAD_IN_PORT;
- }
+ struct odputil_keybuf keybuf;
+ struct dpif_flow_stats stats;
- error = ofpacts_check(ofpacts, ofpacts_len, flow, ofproto->max_ports);
- if (!error) {
- struct odputil_keybuf keybuf;
- struct dpif_flow_stats stats;
+ struct ofpbuf key;
- struct ofpbuf key;
+ struct action_xlate_ctx ctx;
+ uint64_t odp_actions_stub[1024 / 8];
+ struct ofpbuf odp_actions;
- struct action_xlate_ctx ctx;
- uint64_t odp_actions_stub[1024 / 8];
- struct ofpbuf odp_actions;
+ ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
+ odp_flow_key_from_flow(&key, flow);
- ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
- odp_flow_key_from_flow(&key, flow);
+ dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
- dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
+ action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, NULL,
+ packet_get_tcp_flags(packet, flow), packet);
+ ctx.resubmit_stats = &stats;
- action_xlate_ctx_init(&ctx, ofproto, flow, flow->vlan_tci, NULL,
- packet_get_tcp_flags(packet, flow), packet);
- ctx.resubmit_stats = &stats;
+ ofpbuf_use_stub(&odp_actions,
+ odp_actions_stub, sizeof odp_actions_stub);
+ xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions);
+ dpif_execute(ofproto->dpif, key.data, key.size,
+ odp_actions.data, odp_actions.size, packet);
+ ofpbuf_uninit(&odp_actions);
- ofpbuf_use_stub(&odp_actions,
- odp_actions_stub, sizeof odp_actions_stub);
- xlate_actions(&ctx, ofpacts, ofpacts_len, &odp_actions);
- dpif_execute(ofproto->dpif, key.data, key.size,
- odp_actions.data, odp_actions.size, packet);
- ofpbuf_uninit(&odp_actions);
- }
- return error;
+ return 0;
}
\f
/* NetFlow. */
ds_put_cstr(&result, s);
free(s);
- flow_extract(packet, priority, tun_id, in_port, &flow);
+ flow_extract(packet, priority, NULL, in_port, &flow);
+ flow.tunnel.tun_id = tun_id;
initial_tci = flow.vlan_tci;
} else {
unixctl_command_reply_error(conn, "Bad command syntax");