cls_rule_from_flow(struct cls_rule *rule, const flow_t *flow,
uint32_t wildcards, unsigned int priority)
{
- 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 odp_flow_key key;
/* Statistics. */
- struct timeval used; /* Last used time, in milliseconds. */
- long long int packet_count; /* Number of packets matched. */
- long long int byte_count; /* Number of bytes matched. */
- uint8_t ip_tos; /* IP TOS value. */
- uint16_t tcp_ctl; /* Bitwise-OR of seen tcp_ctl values. */
+ struct timeval used; /* Last used time, in milliseconds. */
+ long long int packet_count; /* Number of packets matched. */
+ long long int byte_count; /* Number of bytes matched. */
+ uint8_t ip_tos; /* IP TOS value. */
+ uint16_t tcp_ctl; /* Bitwise-OR of seen tcp_ctl values. */
/* Actions. */
union odp_action *actions;
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 *, flow_t *,
+ struct ofpbuf *, struct odp_flow_key *,
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 odp_flow_key *key)
{
struct dp_netdev_flow *flow;
- assert(!key->reserved[0] && !key->reserved[1] && !key->reserved[2]);
HMAP_FOR_EACH_WITH_HASH (flow, struct dp_netdev_flow, node,
- flow_hash(key, 0), &dp->flow_table) {
- if (flow_equal(&flow->key, key)) {
+ odp_flow_key_hash(key, 0), &dp->flow_table) {
+ if (odp_flow_key_equal(&flow->key, key)) {
return flow;
}
}
flow = xzalloc(sizeof *flow);
flow->key = odp_flow->key;
- memset(flow->key.reserved, 0, sizeof flow->key.reserved);
error = set_flow_actions(flow, odp_flow);
if (error) {
return error;
}
- hmap_insert(&dp->flow_table, &flow->node, flow_hash(&flow->key, 0));
+ hmap_insert(&dp->flow_table, &flow->node,
+ odp_flow_key_hash(&flow->key, 0));
return 0;
}
struct dp_netdev *dp = get_dp_netdev(dpif);
struct ofpbuf copy;
bool mutates;
+ struct odp_flow_key key;
flow_t flow;
int error;
copy = *packet;
}
flow_extract(©, in_port, &flow);
- error = dp_netdev_execute_actions(dp, ©, &flow, actions, n_actions);
+ odp_flow_key_from_flow(&key, &flow);
+ 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,
+ const struct odp_flow_key *key,
const struct ofpbuf *packet)
{
time_timeval(&flow->used);
struct ofpbuf *packet)
{
struct dp_netdev_flow *flow;
- flow_t key;
+ struct odp_flow_key key;
+ flow_t f;
- if (flow_extract(packet, port->port_no, &key) && dp->drop_frags) {
+ if (flow_extract(packet, port->port_no, &f) && dp->drop_frags) {
dp->n_frags++;
return;
}
+ odp_flow_key_from_flow(&key, &f);
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
* bits outside of 'mask'.
*/
static void
-dp_netdev_modify_vlan_tci(struct ofpbuf *packet, flow_t *key,
+dp_netdev_modify_vlan_tci(struct ofpbuf *packet, struct odp_flow_key *key,
uint16_t tci, uint16_t mask)
{
struct vlan_eth_header *veh;
}
static void
-dp_netdev_strip_vlan(struct ofpbuf *packet, flow_t *key)
+dp_netdev_strip_vlan(struct ofpbuf *packet, struct odp_flow_key *key)
{
struct vlan_eth_header *veh = packet->l2;
if (veh->veth_type == htons(ETH_TYPE_VLAN)) {
}
static void
-dp_netdev_set_dl_src(struct ofpbuf *packet, flow_t *key,
+dp_netdev_set_dl_src(struct ofpbuf *packet, struct odp_flow_key *key,
const uint8_t dl_addr[ETH_ADDR_LEN])
{
struct eth_header *eh = packet->l2;
}
static void
-dp_netdev_set_dl_dst(struct ofpbuf *packet, flow_t *key,
+dp_netdev_set_dl_dst(struct ofpbuf *packet, struct odp_flow_key *key,
const uint8_t dl_addr[ETH_ADDR_LEN])
{
struct eth_header *eh = packet->l2;
}
static void
-dp_netdev_set_nw_addr(struct ofpbuf *packet, flow_t *key,
+dp_netdev_set_nw_addr(struct ofpbuf *packet, struct odp_flow_key *key,
const struct odp_action_nw_addr *a)
{
if (key->dl_type == htons(ETH_TYPE_IP)) {
}
static void
-dp_netdev_set_nw_tos(struct ofpbuf *packet, flow_t *key,
+dp_netdev_set_nw_tos(struct ofpbuf *packet, struct odp_flow_key *key,
const struct odp_action_nw_tos *a)
{
if (key->dl_type == htons(ETH_TYPE_IP)) {
}
static void
-dp_netdev_set_tp_port(struct ofpbuf *packet, flow_t *key,
+dp_netdev_set_tp_port(struct ofpbuf *packet, struct odp_flow_key *key,
const struct odp_action_tp_port *a)
{
- if (key->dl_type == htons(ETH_TYPE_IP)) {
+ if (key->dl_type == htons(ETH_TYPE_IP)) {
uint16_t *field;
if (key->nw_proto == IPPROTO_TCP) {
struct tcp_header *th = packet->l4;
dp_netdev_output_port(struct dp_netdev *dp, struct ofpbuf *packet,
uint16_t out_port)
{
- struct dp_netdev_port *p = dp->ports[out_port];
+ struct dp_netdev_port *p = dp->ports[out_port];
if (p) {
netdev_send(p->netdev, packet);
}
dp_netdev_output_group(struct dp_netdev *dp, uint16_t group, uint16_t in_port,
struct ofpbuf *packet)
{
- struct odp_port_group *g = &dp->groups[group];
- int i;
+ struct odp_port_group *g = &dp->groups[group];
+ int i;
- for (i = 0; i < g->n_ports; i++) {
+ for (i = 0; i < g->n_ports; i++) {
uint16_t out_port = g->ports[i];
if (out_port != in_port) {
dp_netdev_output_port(dp, packet, out_port);
}
- }
+ }
}
static int
static int
dp_netdev_execute_actions(struct dp_netdev *dp,
- struct ofpbuf *packet, flow_t *key,
+ struct ofpbuf *packet, struct odp_flow_key *key,
const union odp_action *actions, int n_actions)
{
int i;
for (i = 0; i < n_actions; i++) {
const union odp_action *a = &actions[i];
- switch (a->type) {
- case ODPAT_OUTPUT:
+ switch (a->type) {
+ case ODPAT_OUTPUT:
dp_netdev_output_port(dp, packet, a->output.port);
- break;
+ break;
- case ODPAT_OUTPUT_GROUP:
- dp_netdev_output_group(dp, a->output_group.group, key->in_port,
+ case ODPAT_OUTPUT_GROUP:
+ dp_netdev_output_group(dp, a->output_group.group, key->in_port,
packet);
- break;
+ break;
- case ODPAT_CONTROLLER:
+ case ODPAT_CONTROLLER:
dp_netdev_output_control(dp, packet, _ODPL_ACTION_NR,
key->in_port, a->controller.arg);
- break;
+ break;
- case ODPAT_SET_VLAN_VID:
- dp_netdev_modify_vlan_tci(packet, key, ntohs(a->vlan_vid.vlan_vid),
+ case ODPAT_SET_VLAN_VID:
+ dp_netdev_modify_vlan_tci(packet, key, ntohs(a->vlan_vid.vlan_vid),
VLAN_VID_MASK);
- break;
+ break;
- case ODPAT_SET_VLAN_PCP:
- dp_netdev_modify_vlan_tci(
- packet, key, a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
- VLAN_PCP_MASK);
- break;
+ case ODPAT_SET_VLAN_PCP:
+ dp_netdev_modify_vlan_tci(
+ packet, key, a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
+ VLAN_PCP_MASK);
+ break;
- case ODPAT_STRIP_VLAN:
- dp_netdev_strip_vlan(packet, key);
- break;
+ case ODPAT_STRIP_VLAN:
+ dp_netdev_strip_vlan(packet, key);
+ break;
- case ODPAT_SET_DL_SRC:
+ case ODPAT_SET_DL_SRC:
dp_netdev_set_dl_src(packet, key, a->dl_addr.dl_addr);
- break;
+ break;
- case ODPAT_SET_DL_DST:
+ case ODPAT_SET_DL_DST:
dp_netdev_set_dl_dst(packet, key, a->dl_addr.dl_addr);
- break;
-
- case ODPAT_SET_NW_SRC:
- case ODPAT_SET_NW_DST:
- dp_netdev_set_nw_addr(packet, key, &a->nw_addr);
- break;
-
- case ODPAT_SET_NW_TOS:
- dp_netdev_set_nw_tos(packet, key, &a->nw_tos);
- break;
-
- case ODPAT_SET_TP_SRC:
- case ODPAT_SET_TP_DST:
- dp_netdev_set_tp_port(packet, key, &a->tp_port);
- break;
- }
- }
+ break;
+
+ case ODPAT_SET_NW_SRC:
+ case ODPAT_SET_NW_DST:
+ dp_netdev_set_nw_addr(packet, key, &a->nw_addr);
+ break;
+
+ case ODPAT_SET_NW_TOS:
+ dp_netdev_set_nw_tos(packet, key, &a->nw_tos);
+ break;
+
+ case ODPAT_SET_TP_SRC:
+ case ODPAT_SET_TP_DST:
+ dp_netdev_set_tp_port(packet, key, &a->tp_port);
+ break;
+ }
+ }
return 0;
}
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);
}
char *
struct ofp_match;
struct ofpbuf;
-typedef struct odp_flow_key flow_t;
+typedef struct flow flow_t;
+struct flow {
+ 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[ETH_ALEN]; /* Ethernet source address. */
+ uint8_t dl_dst[ETH_ALEN]; /* 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 33
+#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 *, 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. */
/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
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->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_ALEN);
+ memcpy(key->dl_dst, flow->dl_dst, ETH_ALEN);
+ 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->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_ALEN);
+ memcpy(flow->dl_dst, key->dl_dst, ETH_ALEN);
+ flow->nw_proto = key->nw_proto;
+ flow->dl_vlan_pcp = key->dl_vlan_pcp;
+ flow->nw_tos = key->nw_tos;
+}
/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
#include <stdbool.h>
#include <stdint.h>
+#include <string.h>
+#include "hash.h"
#include "openflow/openflow.h"
#include "openvswitch/datapath-protocol.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->flags = flags;
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;
if (!dpif_flow_del(p->dpif, &odp_flow)) {
if (rule->cr.wc.wildcards) {
size_t i = 0;
LIST_FOR_EACH (subrule, struct rule, 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. */
/* Get updated flow stats. */
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);
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) {
COVERAGE_INC(ofproto_unexpected_rule);
dpif_flow_del(p->dpif, f);
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);