The current code has a simple mapping between datapath and OpenFlow port
numbers (the port numbers were the same other than OFPP_LOCAL which maps
to datapath port 0). Since the translation was know at compile time,
this allowed different layers to easily translate between the two, so
the translation often occurred late.
A future commit will break this simple mapping, so this commit draws a
line between where datapath and OpenFlow port numbers are used. The
ofproto-dpif layer will be responsible for the translations. Callers
above will use OpenFlow port numbers. Providers below will use
datapath port numbers.
Signed-off-by: Justin Pettit <jpettit@nicira.com>
flow_extract(&packet, 0, NULL, 0, &flow);
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
flow_extract(&packet, 0, NULL, 0, &flow);
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
- odp_flow_key_from_flow(&key, &flow);
+ odp_flow_key_from_flow(&key, &flow, OVSP_NONE);
ofpbuf_use_stack(&actions, &action, sizeof action);
nl_msg_put_u32(&actions, OVS_ACTION_ATTR_OUTPUT, port_no);
ofpbuf_use_stack(&actions, &action, sizeof action);
nl_msg_put_u32(&actions, OVS_ACTION_ATTR_OUTPUT, port_no);
struct ofpbuf buf;
ofpbuf_use_stack(&buf, &state->keybuf, sizeof state->keybuf);
struct ofpbuf buf;
ofpbuf_use_stack(&buf, &state->keybuf, sizeof state->keybuf);
- odp_flow_key_from_flow(&buf, &flow->key);
+ odp_flow_key_from_flow(&buf, &flow->key, flow->key.in_port);
*key = buf.data;
*key_len = buf.size;
*key = buf.data;
*key_len = buf.size;
if (packet->size < ETH_HEADER_LEN) {
return;
}
if (packet->size < ETH_HEADER_LEN) {
return;
}
- flow_extract(packet, 0, NULL, odp_port_to_ofp_port(port->port_no), &key);
+ flow_extract(packet, 0, NULL, port->port_no, &key);
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
dp_netdev_flow_used(flow, packet);
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
dp_netdev_flow_used(flow, packet);
buf = &u->buf;
ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
buf = &u->buf;
ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
- odp_flow_key_from_flow(buf, flow);
+ odp_flow_key_from_flow(buf, flow, flow->in_port);
key_len = buf->size;
ofpbuf_pull(buf, key_len);
ofpbuf_reserve(buf, 2);
key_len = buf->size;
ofpbuf_pull(buf, key_len);
ofpbuf_reserve(buf, 2);
flow_wildcards_init_exact(struct flow_wildcards *wc)
{
memset(&wc->masks, 0xff, sizeof wc->masks);
flow_wildcards_init_exact(struct flow_wildcards *wc)
{
memset(&wc->masks, 0xff, sizeof wc->masks);
- memset(wc->masks.zeros, 0, sizeof wc->masks.zeros);
}
/* Returns true if 'wc' matches every packet, false if 'wc' fixes any bits or
}
/* Returns true if 'wc' matches every packet, false if 'wc' fixes any bits or
+/*
+* A flow in the network.
+*
+* The meaning of 'in_port' is context-dependent. In most cases, it is a
+* 16-bit OpenFlow 1.0 port number. In the software datapath interface (dpif)
+* layer and its implementations (e.g. dpif-linux, dpif-netdev), it is instead
+* a 32-bit datapath port number.
+*/
struct flow {
struct flow_tnl tunnel; /* Encapsulating tunnel parameters. */
ovs_be64 metadata; /* OpenFlow Metadata. */
struct flow {
struct flow_tnl tunnel; /* Encapsulating tunnel parameters. */
ovs_be64 metadata; /* OpenFlow Metadata. */
ovs_be32 nw_src; /* IPv4 source address. */
ovs_be32 nw_dst; /* IPv4 destination address. */
ovs_be32 ipv6_label; /* IPv6 flow label. */
ovs_be32 nw_src; /* IPv4 source address. */
ovs_be32 nw_dst; /* IPv4 destination address. */
ovs_be32 ipv6_label; /* IPv6 flow label. */
- uint16_t in_port; /* OpenFlow port number of input port. */
+ uint32_t in_port; /* Input port. OpenFlow port number
+ unless in DPIF code, in which case it
+ is the datapath port number. */
ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
ovs_be16 dl_type; /* Ethernet frame type. */
ovs_be16 tp_src; /* TCP/UDP source port. */
ovs_be16 vlan_tci; /* If 802.1Q, TCI | VLAN_CFI; otherwise 0. */
ovs_be16 dl_type; /* Ethernet frame type. */
ovs_be16 tp_src; /* TCP/UDP source port. */
uint8_t arp_tha[6]; /* ARP/ND target hardware address. */
uint8_t nw_ttl; /* IP TTL/Hop Limit. */
uint8_t nw_frag; /* FLOW_FRAG_* flags. */
uint8_t arp_tha[6]; /* ARP/ND target hardware address. */
uint8_t nw_ttl; /* IP TTL/Hop Limit. */
uint8_t nw_frag; /* FLOW_FRAG_* flags. */
- uint8_t zeros[2]; /* Must be zero. */
};
BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
};
BUILD_ASSERT_DECL(sizeof(struct flow) % 4 == 0);
}
/* Appends a representation of 'flow' as OVS_KEY_ATTR_* attributes to 'buf'.
}
/* Appends a representation of 'flow' as OVS_KEY_ATTR_* attributes to 'buf'.
+ * 'flow->in_port' is ignored (since it is likely to be an OpenFlow port
+ * number rather than a datapath port number). Instead, if 'odp_in_port'
+ * is anything other than OVSP_NONE, it is included in 'buf' as the input
+ * port.
*
* 'buf' must have at least ODPUTIL_FLOW_KEY_BYTES bytes of space, or be
* capable of being expanded to allow for that much space. */
void
*
* 'buf' must have at least ODPUTIL_FLOW_KEY_BYTES bytes of space, or be
* capable of being expanded to allow for that much space. */
void
-odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow)
+odp_flow_key_from_flow(struct ofpbuf *buf, const struct flow *flow,
+ uint32_t odp_in_port)
{
struct ovs_key_ethernet *eth_key;
size_t encap;
{
struct ovs_key_ethernet *eth_key;
size_t encap;
nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tunnel.tun_id);
}
nl_msg_put_be64(buf, OVS_KEY_ATTR_TUN_ID, flow->tunnel.tun_id);
}
- if (flow->in_port != OFPP_NONE && flow->in_port != OFPP_CONTROLLER) {
- nl_msg_put_u32(buf, OVS_KEY_ATTR_IN_PORT,
- ofp_port_to_odp_port(flow->in_port));
+ if (odp_in_port != OVSP_NONE) {
+ nl_msg_put_u32(buf, OVS_KEY_ATTR_IN_PORT, odp_in_port);
}
eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET,
}
eth_key = nl_msg_put_unspec_uninit(buf, OVS_KEY_ATTR_ETHERNET,
* structure in 'flow'. Returns an ODP_FIT_* value that indicates how well
* 'key' fits our expectations for what a flow key should contain.
*
* structure in 'flow'. Returns an ODP_FIT_* value that indicates how well
* 'key' fits our expectations for what a flow key should contain.
*
+ * The 'in_port' will be the datapath's understanding of the port. The
+ * caller will need to translate with odp_port_to_ofp_port() if the
+ * OpenFlow port is needed.
+ *
* This function doesn't take the packet itself as an argument because none of
* the currently understood OVS_KEY_ATTR_* attributes require it. Currently,
* it is always possible to infer which additional attribute(s) should appear
* This function doesn't take the packet itself as an argument because none of
* the currently understood OVS_KEY_ATTR_* attributes require it. Currently,
* it is always possible to infer which additional attribute(s) should appear
odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
struct flow *flow)
{
odp_flow_key_to_flow(const struct nlattr *key, size_t key_len,
struct flow *flow)
{
- static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1];
uint64_t expected_attrs;
uint64_t present_attrs;
const struct nlattr *attrs[OVS_KEY_ATTR_MAX + 1];
uint64_t expected_attrs;
uint64_t present_attrs;
}
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IN_PORT)) {
}
if (present_attrs & (UINT64_C(1) << OVS_KEY_ATTR_IN_PORT)) {
- uint32_t in_port = nl_attr_get_u32(attrs[OVS_KEY_ATTR_IN_PORT]);
- if (in_port >= UINT16_MAX || in_port >= OFPP_MAX) {
- VLOG_ERR_RL(&rl, "in_port %"PRIu32" out of supported range",
- in_port);
- return ODP_FIT_ERROR;
- }
- flow->in_port = odp_port_to_ofp_port(in_port);
+ flow->in_port = nl_attr_get_u32(attrs[OVS_KEY_ATTR_IN_PORT]);
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IN_PORT;
} else {
expected_attrs |= UINT64_C(1) << OVS_KEY_ATTR_IN_PORT;
} else {
- flow->in_port = OFPP_NONE;
+ flow->in_port = OVSP_NONE;
case OFPP_LOCAL:
return OVSP_LOCAL;
case OFPP_NONE:
case OFPP_LOCAL:
return OVSP_LOCAL;
case OFPP_NONE:
return OVSP_NONE;
default:
return ofp_port;
return OVSP_NONE;
default:
return ofp_port;
int odp_flow_key_from_string(const char *s, const struct simap *port_names,
struct ofpbuf *);
int odp_flow_key_from_string(const char *s, const struct simap *port_names,
struct ofpbuf *);
-void odp_flow_key_from_flow(struct ofpbuf *, const struct flow *);
+void odp_flow_key_from_flow(struct ofpbuf *, const struct flow *,
+ uint32_t odp_in_port);
uint32_t odp_flow_key_hash(const struct nlattr *, size_t);
uint32_t odp_flow_key_hash(const struct nlattr *, size_t);
enum odp_key_fitness fitness;
fitness = odp_flow_key_to_flow(key, key_len, flow);
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;
}
if (fitness == ODP_FIT_ERROR) {
return fitness;
}
int error;
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
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);
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);
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;
}
if (fitness == ODP_FIT_ERROR) {
return NULL;
}
struct ofpbuf *key)
{
if (!subfacet->key) {
struct ofpbuf *key)
{
if (!subfacet->key) {
+ struct flow *flow = &subfacet->facet->flow;
+
ofpbuf_use_stack(key, keybuf, sizeof *keybuf);
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);
}
} else {
ofpbuf_use_const(key, subfacet->key, subfacet->key_len);
}
}
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
}
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);
ofpbuf_init(&odp_actions, 32);
compose_sflow_action(ofproto, &odp_actions, &flow, odp_port);
struct ofpbuf odp_actions;
ofpbuf_use_stack(&key, &keybuf, sizeof keybuf);
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(flow->in_port));
dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
dpif_flow_stats_extract(flow, packet, time_msec(), &stats);
flows = xmalloc(N_FLOWS * sizeof *flows);
for (i = 0; i < N_FLOWS; i++) {
random_bytes(&flows[i], sizeof flows[i]);
flows = xmalloc(N_FLOWS * sizeof *flows);
for (i = 0; i < N_FLOWS; i++) {
random_bytes(&flows[i], sizeof flows[i]);
- memset(flows[i].zeros, 0, sizeof flows[i].zeros);
flows[i].regs[0] = OFPP_NONE;
}
flows[i].regs[0] = OFPP_NONE;
}
struct flow flow;
random_bytes(&flow, sizeof flow);
struct flow flow;
random_bytes(&flow, sizeof flow);
- memset(flow.zeros, 0, sizeof flow.zeros);
mp.max_link = n - 1;
multipath_execute(&mp, &flow);
mp.max_link = n - 1;
multipath_execute(&mp, &flow);
/* Convert cls_rule back to odp_key. */
ofpbuf_uninit(&odp_key);
ofpbuf_init(&odp_key, 0);
/* Convert cls_rule back to odp_key. */
ofpbuf_uninit(&odp_key);
ofpbuf_init(&odp_key, 0);
- odp_flow_key_from_flow(&odp_key, &flow);
+ odp_flow_key_from_flow(&odp_key, &flow, flow.in_port);
if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) {
printf ("too long: %zu > %d\n",
if (odp_key.size > ODPUTIL_FLOW_KEY_BYTES) {
printf ("too long: %zu > %d\n",