/* Configuration parameters. */
enum { N_QUEUES = 2 }; /* Number of queues for dpif_recv(). */
enum { MAX_QUEUE_LEN = 100 }; /* Maximum number of packets per queue. */
-enum { N_GROUPS = 16 }; /* Number of port groups. */
enum { MAX_PORTS = 256 }; /* Maximum number of ports. */
enum { MAX_FLOWS = 65536 }; /* Maximum number of flows in flow table. */
bool drop_frags; /* Drop all IP fragments, if true. */
struct ovs_queue queues[N_QUEUES]; /* Messages queued for dpif_recv(). */
struct hmap flow_table; /* Flow table. */
- struct odp_port_group groups[N_GROUPS];
/* Statistics. */
long long int n_frags; /* Number of dropped IP fragments. */
/* 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 *
queue_init(&dp->queues[i]);
}
hmap_init(&dp->flow_table);
- for (i = 0; i < N_GROUPS; i++) {
- dp->groups[i].ports = NULL;
- dp->groups[i].n_ports = 0;
- dp->groups[i].group = i;
- }
list_init(&dp->port_list);
error = do_add_port(dp, name, ODP_PORT_INTERNAL, ODPP_LOCAL);
if (error) {
queue_destroy(&dp->queues[i]);
}
hmap_destroy(&dp->flow_table);
- for (i = 0; i < N_GROUPS; i++) {
- free(dp->groups[i].ports);
- }
dp_netdevs[dp->dp_idx] = NULL;
list_remove(&dp->node);
free(dp);
stats->max_capacity = MAX_FLOWS;
stats->n_ports = dp->n_ports;
stats->max_ports = MAX_PORTS;
- stats->max_groups = N_GROUPS;
stats->n_frags = dp->n_frags;
stats->n_hit = dp->n_hit;
stats->n_missed = dp->n_missed;
{
struct dp_netdev_port *port;
- LIST_FOR_EACH (port, struct dp_netdev_port, node, &dp->port_list) {
+ LIST_FOR_EACH (port, node, &dp->port_list) {
if (!strcmp(netdev_get_name(port->netdev), devname)) {
*portp = port;
return 0;
{
struct dp_netdev_flow *flow, *next;
- HMAP_FOR_EACH_SAFE (flow, next, struct dp_netdev_flow, node,
- &dp->flow_table) {
+ HMAP_FOR_EACH_SAFE (flow, next, node, &dp->flow_table) {
dp_netdev_free_flow(dp, flow);
}
}
int i;
i = 0;
- LIST_FOR_EACH (port, struct dp_netdev_port, node, &dp->port_list) {
+ LIST_FOR_EACH (port, node, &dp->port_list) {
struct odp_port *odp_port = &ports[i];
if (i >= n) {
break;
}
}
-static int
-get_port_group(const struct dpif *dpif, int group_no,
- struct odp_port_group **groupp)
-{
- struct dp_netdev *dp = get_dp_netdev(dpif);
-
- if (group_no >= 0 && group_no < N_GROUPS) {
- *groupp = &dp->groups[group_no];
- return 0;
- } else {
- *groupp = NULL;
- return EINVAL;
- }
-}
-
-static int
-dpif_netdev_port_group_get(const struct dpif *dpif, int group_no,
- uint16_t ports[], int n)
-{
- struct odp_port_group *group;
- int error;
-
- if (n < 0) {
- return -EINVAL;
- }
-
- error = get_port_group(dpif, group_no, &group);
- if (!error) {
- memcpy(ports, group->ports, MIN(n, group->n_ports) * sizeof *ports);
- return group->n_ports;
- } else {
- return -error;
- }
-}
-
-static int
-dpif_netdev_port_group_set(struct dpif *dpif, int group_no,
- const uint16_t ports[], int n)
-{
- struct odp_port_group *group;
- int error;
-
- if (n < 0 || n > MAX_PORTS) {
- return EINVAL;
- }
-
- error = get_port_group(dpif, group_no, &group);
- if (!error) {
- free(group->ports);
- group->ports = xmemdup(ports, n * sizeof *group->ports);
- group->n_ports = n;
- group->group = group_no;
- }
- return error;
-}
-
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, struct dp_netdev_flow, node,
- flow_hash(key, 0), &dp->flow_table) {
+ 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;
}
break;
- case ODPAT_OUTPUT_GROUP:
- *mutates = true;
- if (a->output_group.group >= N_GROUPS) {
- return EINVAL;
- }
- break;
-
case ODPAT_CONTROLLER:
break;
- case ODPAT_SET_VLAN_VID:
- *mutates = true;
- if (a->vlan_vid.vlan_vid & htons(~VLAN_VID_MASK)) {
- return EINVAL;
- }
- break;
-
- case ODPAT_SET_VLAN_PCP:
+ case ODPAT_SET_DL_TCI:
*mutates = true;
- if (a->vlan_pcp.vlan_pcp & ~(VLAN_PCP_MASK >> VLAN_PCP_SHIFT)) {
+ if (a->dl_tci.tci & htons(VLAN_CFI)) {
return EINVAL;
}
break;
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);
int i;
i = 0;
- HMAP_FOR_EACH (flow, struct dp_netdev_flow, node, &dp->flow_table) {
+ HMAP_FOR_EACH (flow, node, &dp->flow_table) {
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);
}
static int
-dpif_netdev_execute(struct dpif *dpif, uint16_t in_port,
+dpif_netdev_execute(struct dpif *dpif,
const union odp_action actions[], int n_actions,
const struct ofpbuf *packet)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
struct ofpbuf copy;
bool mutates;
- flow_t flow;
+ struct flow key;
int error;
if (packet->size < ETH_HEADER_LEN || packet->size > UINT16_MAX) {
* if we don't. */
copy = *packet;
}
- flow_extract(©, 0, in_port, &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;
struct dp_netdev *dp;
ofpbuf_init(&packet, DP_NETDEV_HEADROOM + max_mtu);
- LIST_FOR_EACH (dp, struct dp_netdev, node, &dp_netdev_list) {
+ LIST_FOR_EACH (dp, node, &dp_netdev_list) {
struct dp_netdev_port *port;
- LIST_FOR_EACH (port, struct dp_netdev_port, node, &dp->port_list) {
+ LIST_FOR_EACH (port, node, &dp->port_list) {
int error;
/* Reset packet contents. */
{
struct dp_netdev *dp;
- LIST_FOR_EACH (dp, struct dp_netdev, node, &dp_netdev_list) {
+ LIST_FOR_EACH (dp, node, &dp_netdev_list) {
struct dp_netdev_port *port;
- LIST_FOR_EACH (port, struct dp_netdev_port, node, &dp->port_list) {
+ LIST_FOR_EACH (port, node, &dp->port_list) {
netdev_recv_wait(port->netdev);
}
}
}
-/* Modify the TCI field of 'packet'. If a VLAN tag is not present, one
- * is added with the TCI field set to 'tci'. If a VLAN tag is present,
- * then 'mask' bits are cleared before 'tci' is logically OR'd into the
- * TCI field.
- *
- * Note that the function does not ensure that 'tci' does not affect
- * bits outside of 'mask'.
+/* Modify the TCI field of 'packet'. If a VLAN tag is present, its TCI field
+ * is replaced by 'tci'. If a VLAN tag is not present, one is added with the
+ * TCI field set to 'tci'.
*/
static void
-dp_netdev_modify_vlan_tci(struct ofpbuf *packet, uint16_t tci, uint16_t mask)
+dp_netdev_set_dl_tci(struct ofpbuf *packet, uint16_t tci)
{
struct vlan_eth_header *veh;
struct eth_header *eh;
eh = packet->l2;
if (packet->size >= sizeof(struct vlan_eth_header)
&& eh->eth_type == htons(ETH_TYPE_VLAN)) {
- /* Clear 'mask' bits, but maintain other TCI bits. */
veh = packet->l2;
- veh->veth_tci &= ~htons(mask);
- veh->veth_tci |= htons(tci);
+ veh->veth_tci = tci;
} else {
/* Insert new 802.1Q header. */
- struct eth_header *eh = packet->l2;
struct vlan_eth_header tmp;
memcpy(tmp.veth_dst, eh->eth_dst, ETH_ADDR_LEN);
memcpy(tmp.veth_src, eh->eth_src, ETH_ADDR_LEN);
tmp.veth_type = htons(ETH_TYPE_VLAN);
- tmp.veth_tci = htons(tci);
+ tmp.veth_tci = tci;
tmp.veth_next_type = eh->eth_type;
veh = ofpbuf_push_uninit(packet, VLAN_HEADER_LEN);
}
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)) {
}
}
-static void
-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;
-
- 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
dp_netdev_output_control(struct dp_netdev *dp, const struct ofpbuf *packet,
int queue_no, int port_no, uint32_t arg)
* 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;
dp_netdev_output_port(dp, packet, a->output.port);
break;
- case ODPAT_OUTPUT_GROUP:
- dp_netdev_output_group(dp, a->output_group.group, key->in_port,
- packet);
- break;
-
case ODPAT_CONTROLLER:
dp_netdev_output_control(dp, packet, _ODPL_ACTION_NR,
key->in_port, a->controller.arg);
break;
- case ODPAT_SET_VLAN_VID:
- dp_netdev_modify_vlan_tci(packet, ntohs(a->vlan_vid.vlan_vid),
- VLAN_VID_MASK);
- break;
-
- case ODPAT_SET_VLAN_PCP:
- dp_netdev_modify_vlan_tci(packet,
- a->vlan_pcp.vlan_pcp << VLAN_PCP_SHIFT,
- VLAN_PCP_MASK);
+ case ODPAT_SET_DL_TCI:
+ dp_netdev_set_dl_tci(packet, a->dl_tci.tci);
break;
case ODPAT_STRIP_VLAN:
dpif_netdev_port_list,
dpif_netdev_port_poll,
dpif_netdev_port_poll_wait,
- dpif_netdev_port_group_get,
- dpif_netdev_port_group_set,
dpif_netdev_flow_get,
dpif_netdev_flow_put,
dpif_netdev_flow_del,