cls_rule_from_flow(const flow_t *flow, uint32_t wildcards,
unsigned int priority, struct cls_rule *rule)
{
- assert(!flow->reserved[0] && !flow->reserved[1] && !flow->reserved[2]);
rule->flow = *flow;
flow_wildcards_init(&rule->wc, wildcards);
rule->priority = priority;
/* A flow in dp_netdev's 'flow_table'. */
struct dp_netdev_flow {
struct hmap_node node; /* Element in dp_netdev's 'flow_table'. */
- flow_t key;
+ struct flow key;
/* Statistics. */
struct timespec used; /* Last used time. */
static int dp_netdev_output_control(struct dp_netdev *, const struct ofpbuf *,
int queue_no, int port_no, uint32_t arg);
static int dp_netdev_execute_actions(struct dp_netdev *,
- struct ofpbuf *, const flow_t *,
+ struct ofpbuf *, struct flow *,
const union odp_action *, int n);
static struct dpif_netdev *
}
static struct dp_netdev_flow *
-dp_netdev_lookup_flow(const struct dp_netdev *dp, const flow_t *key)
+dp_netdev_lookup_flow(const struct dp_netdev *dp, const struct flow *key)
{
struct dp_netdev_flow *flow;
- assert(!key->reserved[0] && !key->reserved[1] && !key->reserved[2]);
HMAP_FOR_EACH_WITH_HASH (flow, node, flow_hash(key, 0), &dp->flow_table) {
if (flow_equal(&flow->key, key)) {
return flow;
return NULL;
}
+/* The caller must fill in odp_flow->key itself. */
static void
answer_flow_query(struct dp_netdev_flow *flow, uint32_t query_flags,
struct odp_flow *odp_flow)
{
if (flow) {
- odp_flow->key = flow->key;
odp_flow->stats.n_packets = flow->packet_count;
odp_flow->stats.n_bytes = flow->byte_count;
odp_flow->stats.used_sec = flow->used.tv_sec;
for (i = 0; i < n; i++) {
struct odp_flow *odp_flow = &flows[i];
- answer_flow_query(dp_netdev_lookup_flow(dp, &odp_flow->key),
+ struct flow key;
+
+ odp_flow_key_to_flow(&odp_flow->key, &key);
+ answer_flow_query(dp_netdev_lookup_flow(dp, &key),
odp_flow->flags, odp_flow);
}
return 0;
int error;
flow = xzalloc(sizeof *flow);
- flow->key = odp_flow->key;
- memset(flow->key.reserved, 0, sizeof flow->key.reserved);
+ odp_flow_key_to_flow(&odp_flow->key, &flow->key);
error = set_flow_actions(flow, odp_flow);
if (error) {
{
struct dp_netdev *dp = get_dp_netdev(dpif);
struct dp_netdev_flow *flow;
+ struct flow key;
- flow = dp_netdev_lookup_flow(dp, &put->flow.key);
+ odp_flow_key_to_flow(&put->flow.key, &key);
+ flow = dp_netdev_lookup_flow(dp, &key);
if (!flow) {
if (put->flags & ODPPF_CREATE) {
if (hmap_count(&dp->flow_table) < MAX_FLOWS) {
{
struct dp_netdev *dp = get_dp_netdev(dpif);
struct dp_netdev_flow *flow;
+ struct flow key;
- flow = dp_netdev_lookup_flow(dp, &odp_flow->key);
+ odp_flow_key_to_flow(&odp_flow->key, &key);
+ flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
answer_flow_query(flow, 0, odp_flow);
dp_netdev_free_flow(dp, flow);
if (i >= n) {
break;
}
- answer_flow_query(flow, 0, &flows[i++]);
+
+ odp_flow_key_from_flow(&flows[i].key, &flow->key);
+ answer_flow_query(flow, 0, &flows[i]);
+ i++;
}
return hmap_count(&dp->flow_table);
}
struct dp_netdev *dp = get_dp_netdev(dpif);
struct ofpbuf copy;
bool mutates;
- flow_t flow;
+ flow_t key;
int error;
if (packet->size < ETH_HEADER_LEN || packet->size > UINT16_MAX) {
* if we don't. */
copy = *packet;
}
- flow_extract(©, 0, -1, &flow);
- error = dp_netdev_execute_actions(dp, ©, &flow, actions, n_actions);
+ flow_extract(©, 0, -1, &key);
+ error = dp_netdev_execute_actions(dp, ©, &key, actions, n_actions);
if (mutates) {
ofpbuf_uninit(©);
}
}
\f
static void
-dp_netdev_flow_used(struct dp_netdev_flow *flow, const flow_t *key,
+dp_netdev_flow_used(struct dp_netdev_flow *flow, struct flow *key,
const struct ofpbuf *packet)
{
time_timespec(&flow->used);
struct ofpbuf *packet)
{
struct dp_netdev_flow *flow;
- flow_t key;
+ struct flow key;
if (packet->size < ETH_HEADER_LEN) {
return;
}
static bool
-is_ip(const struct ofpbuf *packet, const flow_t *key)
+is_ip(const struct ofpbuf *packet, const struct flow *key)
{
return key->dl_type == htons(ETH_TYPE_IP) && packet->l4;
}
static void
-dp_netdev_set_nw_addr(struct ofpbuf *packet, const flow_t *key,
+dp_netdev_set_nw_addr(struct ofpbuf *packet, struct flow *key,
const struct odp_action_nw_addr *a)
{
if (is_ip(packet, key)) {
}
static void
-dp_netdev_set_nw_tos(struct ofpbuf *packet, const flow_t *key,
+dp_netdev_set_nw_tos(struct ofpbuf *packet, struct flow *key,
const struct odp_action_nw_tos *a)
{
if (is_ip(packet, key)) {
}
static void
-dp_netdev_set_tp_port(struct ofpbuf *packet, const flow_t *key,
+dp_netdev_set_tp_port(struct ofpbuf *packet, struct flow *key,
const struct odp_action_tp_port *a)
{
if (is_ip(packet, key)) {
* screwy or truncated header fields or one whose inner and outer Ethernet
* address differ. */
static bool
-dp_netdev_is_spoofed_arp(struct ofpbuf *packet, const struct odp_flow_key *key)
+dp_netdev_is_spoofed_arp(struct ofpbuf *packet, const struct flow *key)
{
struct arp_eth_header *arp;
struct eth_header *eth;
static int
dp_netdev_execute_actions(struct dp_netdev *dp,
- struct ofpbuf *packet, const flow_t *key,
+ struct ofpbuf *packet, struct flow *key,
const union odp_action *actions, int n_actions)
{
int i;
case ODPAT_SET_VLAN_VID:
dp_netdev_modify_vlan_tci(packet, ntohs(a->vlan_vid.vlan_vid),
VLAN_VID_MASK);
- break;
+ break;
case ODPAT_SET_VLAN_PCP:
dp_netdev_modify_vlan_tci(packet,
static void
log_flow_message(const struct dpif *dpif, int error, const char *operation,
- const flow_t *flow, const struct odp_flow_stats *stats,
+ const struct odp_flow_key *flow,
+ const struct odp_flow_stats *stats,
const union odp_action *actions, size_t n_actions)
{
struct ds ds = DS_EMPTY_INITIALIZER;
if (error) {
ds_put_format(&ds, "(%s) ", strerror(error));
}
- flow_format(&ds, flow);
+ format_odp_flow_key(&ds, flow);
if (stats) {
ds_put_cstr(&ds, ", ");
format_odp_flow_stats(&ds, stats);
memcpy(flow->dl_dst, match->dl_dst, ETH_ADDR_LEN);
flow->nw_tos = match->nw_tos;
flow->nw_proto = match->nw_proto;
- memset(flow->reserved, 0, sizeof flow->reserved);
-
if (flow_wildcards) {
*flow_wildcards = wildcards;
}
struct ofp_match;
struct ofpbuf;
-typedef struct odp_flow_key flow_t;
+typedef struct flow flow_t;
+struct flow {
+ uint32_t tun_id; /* Encapsulating tunnel ID. */
+ uint32_t nw_src; /* IP source address. */
+ uint32_t nw_dst; /* IP destination address. */
+ uint16_t in_port; /* Input switch port. */
+ uint16_t dl_vlan; /* Input VLAN. */
+ uint16_t dl_type; /* Ethernet frame type. */
+ uint16_t tp_src; /* TCP/UDP source port. */
+ uint16_t tp_dst; /* TCP/UDP destination port. */
+ uint8_t dl_src[6]; /* Ethernet source address. */
+ uint8_t dl_dst[6]; /* Ethernet destination address. */
+ uint8_t nw_proto; /* IP protocol or low 8 bits of ARP opcode. */
+ uint8_t dl_vlan_pcp; /* Input VLAN priority. */
+ uint8_t nw_tos; /* IP ToS (DSCP field, 6 bits). */
+};
+
+/* Assert that there are FLOW_SIG_SIZE bytes of significant data in "struct
+ * flow", followed by FLOW_PAD_SIZE bytes of padding. */
+#define FLOW_SIG_SIZE 37
+#define FLOW_PAD_SIZE 3
+BUILD_ASSERT_DECL(offsetof(struct flow, nw_tos) == FLOW_SIG_SIZE - 1);
+BUILD_ASSERT_DECL(sizeof(((struct flow *)0)->nw_tos) == 1);
+BUILD_ASSERT_DECL(sizeof(struct flow) == FLOW_SIG_SIZE + FLOW_PAD_SIZE);
int flow_extract(struct ofpbuf *, uint32_t tun_id, uint16_t in_port, flow_t *);
void flow_extract_stats(const flow_t *flow, struct ofpbuf *packet,
static inline int
flow_compare(const flow_t *a, const flow_t *b)
{
- return memcmp(a, b, sizeof *a);
+ return memcmp(a, b, FLOW_SIG_SIZE);
}
static inline bool
static inline size_t
flow_hash(const flow_t *flow, uint32_t basis)
{
- BUILD_ASSERT_DECL(!(sizeof *flow % sizeof(uint32_t)));
- return hash_words((const uint32_t *) flow,
- sizeof *flow / sizeof(uint32_t), basis);
+ return hash_bytes(flow, FLOW_SIG_SIZE, basis);
}
/* Information on wildcards for a flow, as a supplement to flow_t. */
return a;
}
+void
+format_odp_flow_key(struct ds *ds, const struct odp_flow_key *key)
+{
+ ds_put_format(ds, "in_port%04x:vlan%d:pcp%d mac"ETH_ADDR_FMT
+ "->"ETH_ADDR_FMT" type%04x proto%"PRId8" tos%"PRIu8
+ " ip"IP_FMT"->"IP_FMT" port%d->%d",
+ key->in_port, ntohs(key->dl_vlan), key->dl_vlan_pcp,
+ ETH_ADDR_ARGS(key->dl_src), ETH_ADDR_ARGS(key->dl_dst),
+ ntohs(key->dl_type), key->nw_proto, key->nw_tos,
+ IP_ARGS(&key->nw_src), IP_ARGS(&key->nw_dst),
+ ntohs(key->tp_src), ntohs(key->tp_dst));
+}
+
void
format_odp_action(struct ds *ds, const union odp_action *a)
{
void
format_odp_flow(struct ds *ds, const struct odp_flow *f)
{
- flow_format(ds, &f->key);
+ format_odp_flow_key(ds, &f->key);
ds_put_cstr(ds, ", ");
format_odp_flow_stats(ds, &f->stats);
ds_put_cstr(ds, ", actions:");
format_odp_actions(ds, f->actions, f->n_actions);
}
+\f
+void
+odp_flow_key_from_flow(struct odp_flow_key *key, const struct flow *flow)
+{
+ key->tun_id = flow->tun_id;
+ key->nw_src = flow->nw_src;
+ key->nw_dst = flow->nw_dst;
+ key->in_port = flow->in_port;
+ key->dl_vlan = flow->dl_vlan;
+ key->dl_type = flow->dl_type;
+ key->tp_src = flow->tp_src;
+ key->tp_dst = flow->tp_dst;
+ memcpy(key->dl_src, flow->dl_src, ETH_ADDR_LEN);
+ memcpy(key->dl_dst, flow->dl_dst, ETH_ADDR_LEN);
+ key->nw_proto = flow->nw_proto;
+ key->dl_vlan_pcp = flow->dl_vlan_pcp;
+ key->nw_tos = flow->nw_tos;
+ memset(key->reserved, 0, sizeof key->reserved);
+}
+void
+odp_flow_key_to_flow(const struct odp_flow_key *key, struct flow *flow)
+{
+ flow->tun_id = key->tun_id;
+ flow->nw_src = key->nw_src;
+ flow->nw_dst = key->nw_dst;
+ flow->in_port = key->in_port;
+ flow->dl_vlan = key->dl_vlan;
+ flow->dl_type = key->dl_type;
+ flow->tp_src = key->tp_src;
+ flow->tp_dst = key->tp_dst;
+ memcpy(flow->dl_src, key->dl_src, ETH_ADDR_LEN);
+ memcpy(flow->dl_dst, key->dl_dst, ETH_ADDR_LEN);
+ flow->nw_proto = key->nw_proto;
+ flow->dl_vlan_pcp = key->dl_vlan_pcp;
+ flow->nw_tos = key->nw_tos;
+}
#include <stdbool.h>
#include <stddef.h>
#include <stdint.h>
+#include <string.h>
+#include "hash.h"
#include "openflow/openflow.h"
#include "openvswitch/datapath-protocol.h"
#include "util.h"
struct ds;
+struct flow;
/* The kernel datapaths limits actions to those that fit in a single page of
* memory, so there is no point in allocating more than that. */
}
}
+void format_odp_flow_key(struct ds *, const struct odp_flow_key *);
void format_odp_action(struct ds *, const union odp_action *);
void format_odp_actions(struct ds *, const union odp_action *actions,
size_t n_actions);
void format_odp_flow_stats(struct ds *, const struct odp_flow_stats *);
void format_odp_flow(struct ds *, const struct odp_flow *);
+void odp_flow_key_from_flow(struct odp_flow_key *, const struct flow *);
+void odp_flow_key_to_flow(const struct odp_flow_key *, struct flow *);
+
+static inline bool
+odp_flow_key_equal(const struct odp_flow_key *a, const struct odp_flow_key *b)
+{
+ return !memcmp(a, b, sizeof *a);
+}
+
+static inline size_t
+odp_flow_key_hash(const struct odp_flow_key *flow, uint32_t basis)
+{
+ BUILD_ASSERT_DECL(!(sizeof *flow % sizeof(uint32_t)));
+ return hash_words((const uint32_t *) flow,
+ sizeof *flow / sizeof(uint32_t), basis);
+}
+
#endif /* odp-util.h */
struct odp_flow_put *put)
{
memset(&put->flow.stats, 0, sizeof put->flow.stats);
- put->flow.key = rule->cr.flow;
+ odp_flow_key_from_flow(&put->flow.key, &rule->cr.flow);
put->flow.actions = rule->odp_actions;
put->flow.n_actions = rule->n_odp_actions;
put->flow.flags = 0;
if (rule->installed) {
struct odp_flow odp_flow;
- odp_flow.key = rule->cr.flow;
+ odp_flow_key_from_flow(&odp_flow.key, &rule->cr.flow);
odp_flow.actions = NULL;
odp_flow.n_actions = 0;
odp_flow.flags = 0;
if (rule->cr.wc.wildcards) {
size_t i = 0;
LIST_FOR_EACH (subrule, list, &rule->list) {
- odp_flows[i++].key = subrule->cr.flow;
+ odp_flow_key_from_flow(&odp_flows[i++].key, &subrule->cr.flow);
packet_count += subrule->packet_count;
byte_count += subrule->byte_count;
}
} else {
- odp_flows[0].key = rule->cr.flow;
+ odp_flow_key_from_flow(&odp_flows[0].key, &rule->cr.flow);
}
/* Fetch up-to-date statistics from the datapath and add them in. */
for (i = 0; i < n_flows; i++) {
struct odp_flow *f = &flows[i];
struct rule *rule;
+ flow_t flow;
+
+ odp_flow_key_to_flow(&f->key, &flow);
rule = rule_from_cls_rule(
- classifier_find_rule_exactly(&p->cls, &f->key, 0, UINT16_MAX));
+ classifier_find_rule_exactly(&p->cls, &flow, 0, UINT16_MAX));
if (rule && rule->installed) {
update_time(p, rule, &f->stats);
* ofproto_update_used() zeroed TCP flags. */
memset(&odp_flow, 0, sizeof odp_flow);
if (rule->installed) {
- odp_flow.key = rule->cr.flow;
+ odp_flow_key_from_flow(&odp_flow.key, &rule->cr.flow);
odp_flow.flags = ODPFF_ZERO_TCP_FLAGS;
dpif_flow_get(ofproto->dpif, &odp_flow);
ETH_ADDR_LEN);
flow.nw_proto = nw_proto_values[get_value(&x, N_NW_PROTO_VALUES)];
flow.nw_tos = nw_tos_values[get_value(&x, N_NW_TOS_VALUES)];
- memset(flow.reserved, 0, sizeof flow.reserved);
for (include = 1; include <= 3; include++) {
cr0 = lookup_with_include_bits(cls, &flow, include);