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 bool facet_is_controller_flow(struct facet *);
struct ofport_dpif {
+ struct hmap_node odp_port_node; /* In ofproto-dpif's "odp_to_ofport_map". */
struct ofport up;
uint32_t odp_port;
static void vsp_remove(struct ofport_dpif *);
static void vsp_add(struct ofport_dpif *, uint16_t realdev_ofp_port, int vid);
+static uint32_t ofp_port_to_odp_port(const struct ofproto_dpif *,
+ uint16_t ofp_port);
+static uint16_t odp_port_to_ofp_port(const struct ofproto_dpif *,
+ uint32_t odp_port);
+
static struct ofport_dpif *
ofport_dpif_cast(const struct ofport *ofport)
{
/* VLAN splinters. */
struct hmap realdev_vid_map; /* (realdev,vid) -> vlandev. */
struct hmap vlandev_map; /* vlandev -> (realdev,vid). */
+
+ /* ODP port to ofp_port mapping. */
+ struct hmap odp_to_ofport_map;
};
/* Defer flow mod completion until "ovs-appctl ofproto/unclog"? (Useful only
\f
/* Factory functions. */
+static void
+init(const struct shash *iface_hints OVS_UNUSED)
+{
+}
+
static void
enumerate_types(struct sset *types)
{
hmap_init(&ofproto->vlandev_map);
hmap_init(&ofproto->realdev_vid_map);
+ hmap_init(&ofproto->odp_to_ofport_map);
+
hmap_insert(&all_ofproto_dpifs, &ofproto->all_ofproto_dpifs_node,
hash_string(ofproto->up.name, 0));
memset(&ofproto->stats, 0, sizeof ofproto->stats);
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;
hmap_destroy(&ofproto->vlandev_map);
hmap_destroy(&ofproto->realdev_vid_map);
+ hmap_destroy(&ofproto->odp_to_ofport_map);
+
dpif_close(ofproto->dpif);
}
}
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 *
{
struct ofport_dpif *port = ofport_dpif_cast(port_);
struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
+ struct dpif_port dpif_port;
+ int error;
ofproto->need_revalidate = REV_RECONFIGURE;
- port->odp_port = ofp_port_to_odp_port(port->up.ofp_port);
port->bundle = NULL;
port->cfm = NULL;
port->tag = tag_create_random();
port->vlandev_vid = 0;
port->carrier_seq = netdev_get_carrier_resets(port->up.netdev);
+ error = dpif_port_query_by_name(ofproto->dpif,
+ netdev_get_name(port->up.netdev),
+ &dpif_port);
+ if (error) {
+ return error;
+ }
+
+ port->odp_port = dpif_port.port_no;
+
+ /* Sanity-check that a mapping doesn't already exist. This
+ * shouldn't happen. */
+ if (odp_port_to_ofp_port(ofproto, port->odp_port) != OFPP_NONE) {
+ VLOG_ERR("port %s already has an OpenFlow port number\n",
+ dpif_port.name);
+ return EBUSY;
+ }
+
+ hmap_insert(&ofproto->odp_to_ofport_map, &port->odp_port_node,
+ hash_int(port->odp_port, 0));
+
if (ofproto->sflow) {
- dpif_sflow_add_port(ofproto->sflow, port_);
+ dpif_sflow_add_port(ofproto->sflow, port_, port->odp_port);
}
return 0;
struct ofport_dpif *port = ofport_dpif_cast(port_);
struct ofproto_dpif *ofproto = ofproto_dpif_cast(port->up.ofproto);
+ hmap_remove(&ofproto->odp_to_ofport_map, &port->odp_port_node);
ofproto->need_revalidate = REV_RECONFIGURE;
bundle_remove(port_);
set_cfm(port_, NULL);
ds = ofproto->sflow = dpif_sflow_create(ofproto->dpif);
HMAP_FOR_EACH (ofport, up.hmap_node, &ofproto->up.ports) {
- dpif_sflow_add_port(ds, &ofport->up);
+ dpif_sflow_add_port(ds, &ofport->up, ofport->odp_port);
}
ofproto->need_revalidate = REV_RECONFIGURE;
}
static struct ofport_dpif *
get_odp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port)
{
- return get_ofp_port(ofproto, odp_port_to_ofp_port(odp_port));
+ return get_ofp_port(ofproto, odp_port_to_ofp_port(ofproto, odp_port));
}
static void
-ofproto_port_from_dpif_port(struct ofproto_port *ofproto_port,
+ofproto_port_from_dpif_port(struct ofproto_dpif *ofproto,
+ struct ofproto_port *ofproto_port,
struct dpif_port *dpif_port)
{
ofproto_port->name = dpif_port->name;
ofproto_port->type = dpif_port->type;
- ofproto_port->ofp_port = odp_port_to_ofp_port(dpif_port->port_no);
+ ofproto_port->ofp_port = odp_port_to_ofp_port(ofproto, dpif_port->port_no);
}
static void
error = dpif_port_query_by_name(ofproto->dpif, devname, &dpif_port);
if (!error) {
- ofproto_port_from_dpif_port(ofproto_port, &dpif_port);
+ ofproto_port_from_dpif_port(ofproto, ofproto_port, &dpif_port);
}
return error;
}
static int
-port_add(struct ofproto *ofproto_, struct netdev *netdev, uint16_t *ofp_portp)
+port_add(struct ofproto *ofproto_, struct netdev *netdev)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- uint16_t odp_port = UINT16_MAX;
- int error;
+ uint32_t odp_port = UINT32_MAX;
- error = dpif_port_add(ofproto->dpif, netdev, &odp_port);
- if (!error) {
- *ofp_portp = odp_port_to_ofp_port(odp_port);
- }
- return error;
+ return dpif_port_add(ofproto->dpif, netdev, &odp_port);
}
static int
port_del(struct ofproto *ofproto_, uint16_t ofp_port)
{
struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
- int error;
+ uint32_t odp_port = ofp_port_to_odp_port(ofproto, ofp_port);
+ int error = 0;
- error = dpif_port_del(ofproto->dpif, ofp_port_to_odp_port(ofp_port));
+ if (odp_port != OFPP_NONE) {
+ error = dpif_port_del(ofproto->dpif, odp_port);
+ }
if (!error) {
struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port);
if (ofport) {
port_dump_next(const struct ofproto *ofproto_ OVS_UNUSED, void *state_,
struct ofproto_port *port)
{
+ struct ofproto_dpif *ofproto = ofproto_dpif_cast(ofproto_);
struct port_dump_state *state = state_;
struct dpif_port dpif_port;
if (dpif_port_dump_next(&state->dump, &dpif_port)) {
- ofproto_port_from_dpif_port(port, &dpif_port);
+ ofproto_port_from_dpif_port(ofproto, port, &dpif_port);
return 0;
} else {
int error = dpif_port_dump_done(&state->dump);
enum odp_key_fitness fitness;
fitness = odp_flow_key_to_flow(key, key_len, flow);
+ flow->in_port = odp_port_to_ofp_port(ofproto, 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);
enum odp_key_fitness fitness;
ovs_be16 initial_tci;
struct flow flow;
+ uint32_t odp_in_port;
fitness = ofproto_dpif_extract_flow_key(ofproto, upcall->key,
upcall->key_len, &flow,
}
memcpy(&cookie, &upcall->userdata, sizeof(cookie));
- dpif_sflow_received(ofproto->sflow, upcall->packet, &flow, &cookie);
+ odp_in_port = ofp_port_to_odp_port(ofproto, flow.in_port);
+ dpif_sflow_received(ofproto->sflow, upcall->packet, &flow,
+ odp_in_port, &cookie);
}
static int
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(ofproto, flow->in_port));
error = dpif_execute(ofproto->dpif, key.data, key.size,
odp_actions, actions_len, packet);
struct flow flow;
fitness = odp_flow_key_to_flow(key, key_len, &flow);
+ flow.in_port = odp_port_to_ofp_port(ofproto, flow.in_port);
if (fitness == ODP_FIT_ERROR) {
return NULL;
}
subfacet_get_key(struct subfacet *subfacet, struct odputil_keybuf *keybuf,
struct ofpbuf *key)
{
+
if (!subfacet->key) {
+ struct ofproto_dpif *ofproto;
+ struct flow *flow = &subfacet->facet->flow;
+
ofpbuf_use_stack(key, keybuf, sizeof *keybuf);
- odp_flow_key_from_flow(key, &subfacet->facet->flow);
+ ofproto = ofproto_dpif_cast(subfacet->facet->rule->up.ofproto);
+ odp_flow_key_from_flow(key, flow,
+ ofp_port_to_odp_port(ofproto, flow->in_port));
} else {
ofpbuf_use_const(key, subfacet->key, subfacet->key_len);
}
}
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;
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(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(ofproto, flow.in_port));
ofpbuf_init(&odp_actions, 32);
compose_sflow_action(ofproto, &odp_actions, &flow, odp_port);
uint32_t pid;
pid = dpif_port_get_pid(ofproto->dpif,
- ofp_port_to_odp_port(flow->in_port));
+ ofp_port_to_odp_port(ofproto, flow->in_port));
return odp_put_userspace_action(pid, cookie, odp_actions);
}
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(ctx->ofproto, 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;
}
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);
}
}
struct ofpbuf odp_actions;
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(ofproto, flow->in_port));
dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
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");
uint32_t realdev_odp_port, ovs_be16 vlan_tci)
{
if (!hmap_is_empty(&ofproto->realdev_vid_map)) {
- uint16_t realdev_ofp_port = odp_port_to_ofp_port(realdev_odp_port);
+ uint16_t realdev_ofp_port;
int vid = vlan_tci_to_vid(vlan_tci);
const struct vlan_splinter *vsp;
+ realdev_ofp_port = odp_port_to_ofp_port(ofproto, realdev_odp_port);
HMAP_FOR_EACH_WITH_HASH (vsp, realdev_vid_node,
hash_realdev_vid(realdev_ofp_port, vid),
&ofproto->realdev_vid_map) {
if (vsp->realdev_ofp_port == realdev_ofp_port
&& vsp->vid == vid) {
- return ofp_port_to_odp_port(vsp->vlandev_ofp_port);
+ return ofp_port_to_odp_port(ofproto, vsp->vlandev_ofp_port);
}
}
}
VLOG_ERR("duplicate vlan device record");
}
}
-\f
+
+static uint32_t
+ofp_port_to_odp_port(const struct ofproto_dpif *ofproto, uint16_t ofp_port)
+{
+ const struct ofport_dpif *ofport = get_ofp_port(ofproto, ofp_port);
+ return ofport ? ofport->odp_port : OVSP_NONE;
+}
+
+static uint16_t
+odp_port_to_ofp_port(const struct ofproto_dpif *ofproto, uint32_t odp_port)
+{
+ struct ofport_dpif *port;
+
+ HMAP_FOR_EACH_IN_BUCKET (port, odp_port_node,
+ hash_int(odp_port, 0),
+ &ofproto->odp_to_ofport_map) {
+ if (port->odp_port == odp_port) {
+ return port->up.ofp_port;
+ }
+ }
+
+ return OFPP_NONE;
+}
+
const struct ofproto_class ofproto_dpif_class = {
+ init,
enumerate_types,
enumerate_names,
del,