/* Maximum depth of flow table recursion (due to resubmit actions) in a
* flow translation. */
-#define MAX_RESUBMIT_RECURSION 32
+#define MAX_RESUBMIT_RECURSION 64
/* Number of implemented OpenFlow tables. */
enum { N_TABLES = 255 };
static struct rule_dpif *rule_dpif_lookup__(struct ofproto_dpif *,
const struct flow *,
uint8_t table);
+static struct rule_dpif *rule_dpif_miss_rule(struct ofproto_dpif *ofproto,
+ const struct flow *flow);
static void rule_credit_stats(struct rule_dpif *,
const struct dpif_flow_stats *);
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
uint32_t orig_skb_priority; /* Priority when packet arrived. */
uint8_t table_id; /* OpenFlow table ID where flow was found. */
uint32_t sflow_n_outputs; /* Number of output ports. */
- uint16_t sflow_odp_port; /* Output port for composing sFlow action. */
+ uint32_t sflow_odp_port; /* Output port for composing sFlow action. */
uint16_t user_cookie_offset;/* Used for user_action_cookie fixup. */
bool exit; /* No further actions should be processed. */
struct flow orig_flow; /* Copy of original flow. */
static struct subfacet *subfacet_create(struct facet *, enum odp_key_fitness,
const struct nlattr *key,
- size_t key_len, ovs_be16 initial_tci);
+ size_t key_len, ovs_be16 initial_tci,
+ long long int now);
static struct subfacet *subfacet_find(struct ofproto_dpif *,
const struct nlattr *key, size_t key_len);
static void subfacet_destroy(struct subfacet *);
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. */
\f
/* Factory functions. */
+static void
+init(const struct shash *iface_hints OVS_UNUSED)
+{
+}
+
static void
enumerate_types(struct sset *types)
{
{
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 ofp_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 *
return ofport->cfm ? cfm_get_fault(ofport->cfm) : -1;
}
+static int
+get_cfm_opup(const struct ofport *ofport_)
+{
+ struct ofport_dpif *ofport = ofport_dpif_cast(ofport_);
+
+ return ofport->cfm ? cfm_get_opup(ofport->cfm) : -1;
+}
+
static int
get_cfm_remote_mpids(const struct ofport *ofport_, const uint64_t **rmps,
size_t *n_rmps)
break;
case PORT_VLAN_TRUNK:
- trunks = (unsigned long *) s->trunks;
+ trunks = CONST_CAST(unsigned long *, s->trunks);
break;
case PORT_VLAN_NATIVE_UNTAGGED:
bitmap_set1(trunks, vlan);
bitmap_set0(trunks, 0);
} else {
- trunks = (unsigned long *) s->trunks;
+ trunks = CONST_CAST(unsigned long *, s->trunks);
}
break;
port_run_fast(ofport);
if (ofport->cfm) {
+ int cfm_opup = cfm_get_opup(ofport->cfm);
+
cfm_run(ofport->cfm);
- enable = enable && !cfm_get_fault(ofport->cfm)
- && cfm_get_opup(ofport->cfm);
+ enable = enable && !cfm_get_fault(ofport->cfm);
+
+ if (cfm_opup >= 0) {
+ enable = enable && cfm_opup;
+ }
}
if (ofport->bundle) {
port_add(struct ofproto *ofproto_, struct netdev *netdev, uint16_t *ofp_portp)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- uint16_t odp_port = UINT16_MAX;
+ uint32_t odp_port = *ofp_portp != OFPP_NONE ? *ofp_portp : UINT32_MAX;
int error;
error = dpif_port_add(ofproto->dpif, netdev, &odp_port);
/* ofproto->stats.rx_packets represents packets that were received on
* some port and we processed internally and dropped (e.g. STP).
- * Account fro them as if they had been forwarded to OFPP_LOCAL. */
+ * Account for them as if they had been forwarded to OFPP_LOCAL. */
if (stats->tx_packets != UINT64_MAX) {
stats->tx_packets += ofproto->stats.rx_packets;
flow_get_metadata(flow, &pin.fmd);
- /* Registers aren't meaningful on a miss. */
- memset(pin.fmd.reg_masks, 0, sizeof pin.fmd.reg_masks);
-
connmgr_send_packet_in(ofproto->up.connmgr, &pin);
}
struct flow_miss_op *ops, size_t *n_ops)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(rule->up.ofproto);
+ long long int now = time_msec();
struct action_xlate_ctx ctx;
struct ofpbuf *packet;
ofpbuf_use_stub(&odp_actions, op->stub, sizeof op->stub);
- dpif_flow_stats_extract(&miss->flow, packet, &stats);
+ dpif_flow_stats_extract(&miss->flow, packet, now, &stats);
rule_credit_stats(rule, &stats);
action_xlate_ctx_init(&ctx, ofproto, &miss->flow, miss->initial_tci,
}
/* Handles 'miss', which matches 'facet'. May add any required datapath
- * operations to 'ops', incrementing '*n_ops' for each new op. */
+ * operations to 'ops', incrementing '*n_ops' for each new op.
+ *
+ * All of the packets in 'miss' are considered to have arrived at time 'now'.
+ * This is really important only for new facets: if we just called time_msec()
+ * here, then the new subfacet or its packets could look (occasionally) as
+ * though it was used some time after the facet was used. That can make a
+ * one-packet flow look like it has a nonzero duration, which looks odd in
+ * e.g. NetFlow statistics. */
static void
handle_flow_miss_with_facet(struct flow_miss *miss, struct facet *facet,
+ long long int now,
struct flow_miss_op *ops, size_t *n_ops)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
subfacet = subfacet_create(facet,
miss->key_fitness, miss->key, miss->key_len,
- miss->initial_tci);
+ miss->initial_tci, now);
LIST_FOR_EACH (packet, list_node, &miss->packets) {
struct flow_miss_op *op = &ops[*n_ops];
subfacet_make_actions(subfacet, packet, &odp_actions);
}
- dpif_flow_stats_extract(&facet->flow, packet, &stats);
+ dpif_flow_stats_extract(&facet->flow, packet, now, &stats);
subfacet_update_stats(subfacet, &stats);
if (subfacet->actions_len) {
struct flow_miss_op *ops, size_t *n_ops)
{
struct facet *facet;
+ long long int now;
uint32_t hash;
/* The caller must ensure that miss->hmap_node.hash contains
}
facet = facet_create(rule, &miss->flow, hash);
+ now = facet->used;
+ } else {
+ now = time_msec();
}
- handle_flow_miss_with_facet(miss, facet, ops, n_ops);
+ handle_flow_miss_with_facet(miss, facet, now, ops, n_ops);
}
/* Like odp_flow_key_to_flow(), this function converts the 'key_len' bytes of
enum odp_key_fitness fitness;
fitness = odp_flow_key_to_flow(key, key_len, flow);
+ flow->in_port = odp_port_to_ofp_port(flow->in_port);
if (fitness == ODP_FIT_ERROR) {
return fitness;
}
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);
int error;
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
- odp_flow_key_from_flow(&key, flow);
+ odp_flow_key_from_flow(&key, flow, ofp_port_to_odp_port(flow->in_port));
error = dpif_execute(ofproto->dpif, key.data, key.size,
odp_actions, actions_len, packet);
const struct ofpact *ofpacts = rule->ofpacts;
size_t ofpacts_len = rule->ofpacts_len;
- if (ofpacts->type == OFPACT_CONTROLLER &&
+ if (ofpacts_len > 0 &&
+ ofpacts->type == OFPACT_CONTROLLER &&
ofpact_next(ofpacts) >= ofpact_end(ofpacts, ofpacts_len)) {
return true;
}
* subfacet_make_actions(). */
static struct subfacet *
subfacet_create(struct facet *facet, enum odp_key_fitness key_fitness,
- const struct nlattr *key, size_t key_len, ovs_be16 initial_tci)
+ const struct nlattr *key, size_t key_len,
+ ovs_be16 initial_tci, long long int now)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(facet->rule->up.ofproto);
uint32_t key_hash = odp_flow_key_hash(key, key_len);
struct subfacet *subfacet;
- subfacet = subfacet_find__(ofproto, key, key_len, key_hash, &facet->flow);
- if (subfacet) {
- if (subfacet->facet == facet) {
- return subfacet;
+ if (list_is_empty(&facet->subfacets)) {
+ subfacet = &facet->one_subfacet;
+ } else {
+ subfacet = subfacet_find__(ofproto, key, key_len, key_hash,
+ &facet->flow);
+ if (subfacet) {
+ if (subfacet->facet == facet) {
+ return subfacet;
+ }
+
+ /* This shouldn't happen. */
+ VLOG_ERR_RL(&rl, "subfacet with wrong facet");
+ subfacet_destroy(subfacet);
}
- /* This shouldn't happen. */
- VLOG_ERR_RL(&rl, "subfacet with wrong facet");
- subfacet_destroy(subfacet);
+ subfacet = xmalloc(sizeof *subfacet);
}
- subfacet = (list_is_empty(&facet->subfacets)
- ? &facet->one_subfacet
- : xmalloc(sizeof *subfacet));
hmap_insert(&ofproto->subfacets, &subfacet->hmap_node, key_hash);
list_push_back(&facet->subfacets, &subfacet->list_node);
subfacet->facet = facet;
subfacet->key = NULL;
subfacet->key_len = 0;
}
- subfacet->used = time_msec();
+ subfacet->used = now;
subfacet->dp_packet_count = 0;
subfacet->dp_byte_count = 0;
subfacet->actions_len = 0;
struct flow flow;
fitness = odp_flow_key_to_flow(key, key_len, &flow);
+ flow.in_port = odp_port_to_ofp_port(flow.in_port);
if (fitness == ODP_FIT_ERROR) {
return NULL;
}
struct ofpbuf *key)
{
if (!subfacet->key) {
+ struct flow *flow = &subfacet->facet->flow;
+
ofpbuf_use_stack(key, keybuf, sizeof *keybuf);
- odp_flow_key_from_flow(key, &subfacet->facet->flow);
+ odp_flow_key_from_flow(key, flow, ofp_port_to_odp_port(flow->in_port));
} else {
ofpbuf_use_const(key, subfacet->key, subfacet->key_len);
}
static struct rule_dpif *
rule_dpif_lookup(struct ofproto_dpif *ofproto, const struct flow *flow)
{
- struct ofport_dpif *port;
struct rule_dpif *rule;
rule = rule_dpif_lookup__(ofproto, flow, 0);
return rule;
}
- port = get_ofp_port(ofproto, flow->in_port);
- if (!port) {
- VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16, flow->in_port);
- return ofproto->miss_rule;
- }
-
- if (port->up.pp.config & OFPUTIL_PC_NO_PACKET_IN) {
- return ofproto->no_packet_in_rule;
- }
- return ofproto->miss_rule;
+ return rule_dpif_miss_rule(ofproto, flow);
}
static struct rule_dpif *
return rule_dpif_cast(rule_from_cls_rule(cls_rule));
}
+static struct rule_dpif *
+rule_dpif_miss_rule(struct ofproto_dpif *ofproto, const struct flow *flow)
+{
+ struct ofport_dpif *port;
+
+ port = get_ofp_port(ofproto, flow->in_port);
+ if (!port) {
+ VLOG_WARN_RL(&rl, "packet-in on unknown port %"PRIu16, flow->in_port);
+ return ofproto->miss_rule;
+ }
+
+ if (port->up.pp.config & OFPUTIL_PC_NO_PACKET_IN) {
+ return ofproto->no_packet_in_rule;
+ }
+ return ofproto->miss_rule;
+}
+
static void
complete_operation(struct rule_dpif *rule)
{
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;
uint64_t odp_actions_stub[1024 / 8];
struct ofpbuf odp_actions;
- dpif_flow_stats_extract(flow, packet, &stats);
+ dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
rule_credit_stats(rule, &stats);
ofpbuf_use_stub(&odp_actions, odp_actions_stub, sizeof odp_actions_stub);
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);
}
const struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofport->up.ofproto);
struct ofpbuf key, odp_actions;
struct odputil_keybuf keybuf;
- uint16_t odp_port;
+ uint32_t odp_port;
struct flow flow;
int error;
- flow_extract((struct ofpbuf *) 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) {
}
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
- odp_flow_key_from_flow(&key, &flow);
+ odp_flow_key_from_flow(&key, &flow, ofp_port_to_odp_port(flow.in_port));
ofpbuf_init(&odp_actions, 32);
compose_sflow_action(ofproto, &odp_actions, &flow, odp_port);
bool check_stp)
{
const struct ofport_dpif *ofport = get_ofp_port(ctx->ofproto, ofp_port);
- uint16_t odp_port = ofp_port_to_odp_port(ofp_port);
+ uint32_t odp_port = ofp_port_to_odp_port(ofp_port);
ovs_be16 flow_vlan_tci = ctx->flow.vlan_tci;
uint8_t flow_nw_tos = ctx->flow.nw_tos;
uint16_t out_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;
}
static void
xlate_table_action(struct action_xlate_ctx *ctx,
- uint16_t in_port, uint8_t table_id)
+ uint16_t in_port, uint8_t table_id, bool may_packet_in)
{
if (ctx->recurse < MAX_RESUBMIT_RECURSION) {
struct ofproto_dpif *ofproto = ctx->ofproto;
ctx->tags |= (rule && rule->tag
? rule->tag
: rule_calculate_tag(&ctx->flow,
- &table->other_table->wc,
+ &table->other_table->mask,
table->basis));
}
}
ctx->resubmit_hook(ctx, rule);
}
+ if (rule == NULL && may_packet_in) {
+ /* TODO:XXX
+ * check if table configuration flags
+ * OFPTC_TABLE_MISS_CONTROLLER, default.
+ * OFPTC_TABLE_MISS_CONTINUE,
+ * OFPTC_TABLE_MISS_DROP
+ * When OF1.0, OFPTC_TABLE_MISS_CONTINUE is used. What to do?
+ */
+ rule = rule_dpif_miss_rule(ofproto, &ctx->flow);
+ }
+
if (rule) {
struct rule_dpif *old_rule = ctx->rule;
table_id = ctx->table_id;
}
- xlate_table_action(ctx, in_port, table_id);
+ xlate_table_action(ctx, in_port, table_id, false);
}
static void
}
static bool
-compose_dec_ttl(struct action_xlate_ctx *ctx)
+compose_dec_ttl(struct action_xlate_ctx *ctx, struct ofpact_cnt_ids *ids)
{
if (ctx->flow.dl_type != htons(ETH_TYPE_IP) &&
ctx->flow.dl_type != htons(ETH_TYPE_IPV6)) {
ctx->flow.nw_ttl--;
return false;
} else {
- execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL, 0);
+ size_t i;
+
+ for (i = 0; i < ids->n_controllers; i++) {
+ execute_controller_action(ctx, UINT16_MAX, OFPR_INVALID_TTL,
+ ids->cnt_ids[i]);
+ }
/* Stop processing for current table. */
return true;
static void
xlate_output_action(struct action_xlate_ctx *ctx,
- uint16_t port, uint16_t max_len)
+ uint16_t port, uint16_t max_len, bool may_packet_in)
{
uint16_t prev_nf_output_iface = ctx->nf_output_iface;
compose_output_action(ctx, ctx->flow.in_port);
break;
case OFPP_TABLE:
- xlate_table_action(ctx, ctx->flow.in_port, 0);
+ xlate_table_action(ctx, ctx->flow.in_port, 0, may_packet_in);
break;
case OFPP_NORMAL:
xlate_normal(ctx);
default:
if (port != ctx->flow.in_port) {
compose_output_action(ctx, port);
+ } else {
+ xlate_report(ctx, "skipping output to input port");
}
break;
}
{
uint64_t port = mf_get_subfield(&or->src, &ctx->flow);
if (port <= UINT16_MAX) {
- xlate_output_action(ctx, port, or->max_len);
+ xlate_output_action(ctx, port, or->max_len, false);
}
}
error = dpif_queue_to_priority(ctx->ofproto->dpif, queue_id, &priority);
if (error) {
/* Fall back to ordinary output action. */
- xlate_output_action(ctx, enqueue->port, 0);
+ xlate_output_action(ctx, enqueue->port, 0, false);
return;
}
if (bundle->dst.field) {
nxm_reg_load(&bundle->dst, port, &ctx->flow);
} else {
- xlate_output_action(ctx, port, 0);
+ xlate_output_action(ctx, port, 0, false);
}
}
}
OFPACT_FOR_EACH (a, ofpacts, ofpacts_len) {
struct ofpact_controller *controller;
+ const struct ofpact_metadata *metadata;
if (ctx->exit) {
break;
switch (a->type) {
case OFPACT_OUTPUT:
xlate_output_action(ctx, ofpact_get_OUTPUT(a)->port,
- ofpact_get_OUTPUT(a)->max_len);
+ ofpact_get_OUTPUT(a)->max_len, true);
break;
case OFPACT_CONTROLLER:
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:
break;
case OFPACT_DEC_TTL:
- if (compose_dec_ttl(ctx)) {
+ if (compose_dec_ttl(ctx, ofpact_get_DEC_TTL(a))) {
goto out;
}
break;
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, ofp_port_to_odp_port(flow->in_port));
- 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, &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. */
const char *tun_id_s = argv[3];
const char *in_port_s = argv[4];
const char *packet_s = argv[5];
- uint16_t in_port = ofp_port_to_odp_port(atoi(in_port_s));
+ uint32_t in_port = atoi(in_port_s);
ovs_be64 tun_id = htonll(strtoull(tun_id_s, NULL, 0));
uint32_t priority = atoi(priority_s);
const char *msg;
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");
}
\f
const struct ofproto_class ofproto_dpif_class = {
+ init,
enumerate_types,
enumerate_names,
del,
set_sflow,
set_cfm,
get_cfm_fault,
+ get_cfm_opup,
get_cfm_remote_mpids,
get_cfm_health,
set_stp,