/*
- * Copyright (c) 2009, 2010, 2011, 2012 Nicira Networks.
+ * Copyright (c) 2009, 2010, 2011, 2012 Nicira, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
enum { QUEUE_MASK = MAX_QUEUE_LEN - 1 };
BUILD_ASSERT_DECL(IS_POW2(MAX_QUEUE_LEN));
+struct dp_netdev_upcall {
+ struct dpif_upcall upcall; /* Queued upcall information. */
+ struct ofpbuf buf; /* ofpbuf instance for upcall.packet. */
+};
+
struct dp_netdev_queue {
- struct dpif_upcall *upcalls[MAX_QUEUE_LEN];
+ struct dp_netdev_upcall upcalls[MAX_QUEUE_LEN];
unsigned int head, tail;
};
long long int used; /* Last used time, in monotonic msecs. */
long long int packet_count; /* Number of packets matched. */
long long int byte_count; /* Number of bytes matched. */
- ovs_be16 tcp_ctl; /* Bitwise-OR of seen tcp_ctl values. */
+ uint8_t tcp_flags; /* Bitwise-OR of seen tcp_flags values. */
/* Actions. */
struct nlattr *actions;
return dpif_netdev_cast(dpif)->dp;
}
+static int
+dpif_netdev_enumerate(struct sset *all_dps)
+{
+ struct shash_node *node;
+
+ SHASH_FOR_EACH(node, &dp_netdevs) {
+ sset_add(all_dps, node->name);
+ }
+ return 0;
+}
+
static struct dpif *
create_dpif_netdev(struct dp_netdev *dp)
{
struct dp_netdev_queue *q = &dp->queues[i];
while (q->tail != q->head) {
- struct dpif_upcall *upcall = q->upcalls[q->tail++ & QUEUE_MASK];
-
- ofpbuf_delete(upcall->packet);
- free(upcall);
+ struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
+ ofpbuf_uninit(&u->buf);
}
}
}
return 0;
}
+static const char* internal_port_type(const struct dp_netdev* dp)
+{
+ if (dp->class == &dpif_netdev_class)
+ return "tap";
+ if (dp->class == &dpif_planetlab_class)
+ return "pltap";
+ return "dummy";
+}
+
static int
do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
uint16_t port_no)
/* XXX reject devices already in some dp_netdev. */
/* Open and validate network device. */
- open_type = (strcmp(type, "internal") ? type
- : dp->class != &dpif_netdev_class ? "dummy"
- : "tap");
+ open_type = (strcmp(type, "internal") ? type : internal_port_type(dp));
error = netdev_open(devname, open_type, &netdev);
if (error) {
return error;
struct dp_netdev *dp = get_dp_netdev(dpif);
int port_no;
- if (dpif->dpif_class != &dpif_netdev_class) {
+ if (dpif->dpif_class != &dpif_netdev_class &&
+ dpif->dpif_class != &dpif_planetlab_class)
+ {
/* If the port name contains a number, try to assign that port number.
* This can make writing unit tests easier because port numbers are
* predictable. */
struct dp_netdev *dp = get_dp_netdev(dpif);
int port_no;
- port_no = choose_port(dpif, netdev);
+ if (*port_nop != UINT16_MAX) {
+ if (*port_nop >= MAX_PORTS) {
+ return EFBIG;
+ } else if (dp->ports[*port_nop]) {
+ return EBUSY;
+ }
+ port_no = *port_nop;
+ } else {
+ port_no = choose_port(dpif, netdev);
+ }
if (port_no >= 0) {
*port_nop = port_no;
return do_add_port(dp, netdev_get_name(netdev),
stats->n_packets = flow->packet_count;
stats->n_bytes = flow->byte_count;
stats->used = flow->used;
- stats->tcp_flags = TCP_FLAGS(flow->tcp_ctl);
+ stats->tcp_flags = flow->tcp_flags;
}
static int
}
static int
-add_flow(struct dpif *dpif, const struct flow *key,
- const struct nlattr *actions, size_t actions_len)
+dp_netdev_flow_add(struct dp_netdev *dp, const struct flow *key,
+ const struct nlattr *actions, size_t actions_len)
{
- struct dp_netdev *dp = get_dp_netdev(dpif);
struct dp_netdev_flow *flow;
int error;
flow->used = 0;
flow->packet_count = 0;
flow->byte_count = 0;
- flow->tcp_ctl = 0;
+ flow->tcp_flags = 0;
}
static int
if (put->stats) {
memset(put->stats, 0, sizeof *put->stats);
}
- return add_flow(dpif, &key, put->actions, put->actions_len);
+ return dp_netdev_flow_add(dp, &key, put->actions,
+ put->actions_len);
} else {
return EFBIG;
}
}
static int
-dpif_netdev_flow_del(struct dpif *dpif,
- const struct nlattr *nl_key, size_t nl_key_len,
- struct dpif_flow_stats *stats)
+dpif_netdev_flow_del(struct dpif *dpif, const struct dpif_flow_del *del)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
struct dp_netdev_flow *flow;
struct flow key;
int error;
- error = dpif_netdev_flow_from_nlattrs(nl_key, nl_key_len, &key);
+ error = dpif_netdev_flow_from_nlattrs(del->key, del->key_len, &key);
if (error) {
return error;
}
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
- if (stats) {
- get_dpif_flow_stats(flow, stats);
+ if (del->stats) {
+ get_dpif_flow_stats(flow, del->stats);
}
dp_netdev_free_flow(dp, flow);
return 0;
}
static int
-dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall)
+dpif_netdev_recv(struct dpif *dpif, struct dpif_upcall *upcall,
+ struct ofpbuf *buf)
{
struct dp_netdev_queue *q = find_nonempty_queue(dpif);
if (q) {
- struct dpif_upcall *u = q->upcalls[q->tail++ & QUEUE_MASK];
- *upcall = *u;
- free(u);
+ struct dp_netdev_upcall *u = &q->upcalls[q->tail++ & QUEUE_MASK];
+
+ *upcall = u->upcall;
+ upcall->packet = buf;
+
+ ofpbuf_uninit(buf);
+ *buf = u->buf;
return 0;
} else {
flow->used = time_msec();
flow->packet_count++;
flow->byte_count += packet->size;
- if (key->dl_type == htons(ETH_TYPE_IP) && key->nw_proto == IPPROTO_TCP) {
- struct tcp_header *th = packet->l4;
- flow->tcp_ctl |= th->tcp_ctl;
- }
+ flow->tcp_flags |= packet_get_tcp_flags(packet, key);
}
static void
if (packet->size < ETH_HEADER_LEN) {
return;
}
- flow_extract(packet, 0, 0, port->port_no, &key);
+ flow_extract(packet, 0, 0, odp_port_to_ofp_port(port->port_no), &key);
flow = dp_netdev_lookup_flow(dp, &key);
if (flow) {
dp_netdev_flow_used(flow, &key, packet);
int queue_no, const struct flow *flow, uint64_t arg)
{
struct dp_netdev_queue *q = &dp->queues[queue_no];
+ struct dp_netdev_upcall *u;
struct dpif_upcall *upcall;
struct ofpbuf *buf;
size_t key_len;
return ENOBUFS;
}
- buf = ofpbuf_new(ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
+ u = &q->upcalls[q->head++ & QUEUE_MASK];
+
+ buf = &u->buf;
+ ofpbuf_init(buf, ODPUTIL_FLOW_KEY_BYTES + 2 + packet->size);
odp_flow_key_from_flow(buf, flow);
key_len = buf->size;
ofpbuf_pull(buf, key_len);
ofpbuf_reserve(buf, 2);
ofpbuf_put(buf, packet->data, packet->size);
- upcall = xzalloc(sizeof *upcall);
+ upcall = &u->upcall;
upcall->type = queue_no;
upcall->packet = buf;
upcall->key = buf->base;
upcall->key_len = key_len;
upcall->userdata = arg;
- q->upcalls[q->head++ & QUEUE_MASK] = upcall;
-
return 0;
}
}
}
+#define DPIF_NETDEV_CLASS_FUNCTIONS \
+ dpif_netdev_enumerate, \
+ dpif_netdev_open, \
+ dpif_netdev_close, \
+ dpif_netdev_destroy, \
+ dpif_netdev_run, \
+ dpif_netdev_wait, \
+ dpif_netdev_get_stats, \
+ dpif_netdev_port_add, \
+ dpif_netdev_port_del, \
+ dpif_netdev_port_query_by_number, \
+ dpif_netdev_port_query_by_name, \
+ dpif_netdev_get_max_ports, \
+ NULL, /* port_get_pid */ \
+ dpif_netdev_port_dump_start, \
+ dpif_netdev_port_dump_next, \
+ dpif_netdev_port_dump_done, \
+ dpif_netdev_port_poll, \
+ dpif_netdev_port_poll_wait, \
+ dpif_netdev_flow_get, \
+ dpif_netdev_flow_put, \
+ dpif_netdev_flow_del, \
+ dpif_netdev_flow_flush, \
+ dpif_netdev_flow_dump_start, \
+ dpif_netdev_flow_dump_next, \
+ dpif_netdev_flow_dump_done, \
+ dpif_netdev_execute, \
+ NULL, /* operate */ \
+ dpif_netdev_recv_set, \
+ dpif_netdev_queue_to_priority, \
+ dpif_netdev_recv, \
+ dpif_netdev_recv_wait, \
+ dpif_netdev_recv_purge, \
+
const struct dpif_class dpif_netdev_class = {
"netdev",
- NULL, /* enumerate */
- dpif_netdev_open,
- dpif_netdev_close,
- dpif_netdev_destroy,
- dpif_netdev_run,
- dpif_netdev_wait,
- dpif_netdev_get_stats,
- dpif_netdev_port_add,
- dpif_netdev_port_del,
- dpif_netdev_port_query_by_number,
- dpif_netdev_port_query_by_name,
- dpif_netdev_get_max_ports,
- NULL, /* port_get_pid */
- dpif_netdev_port_dump_start,
- dpif_netdev_port_dump_next,
- dpif_netdev_port_dump_done,
- dpif_netdev_port_poll,
- dpif_netdev_port_poll_wait,
- dpif_netdev_flow_get,
- dpif_netdev_flow_put,
- dpif_netdev_flow_del,
- dpif_netdev_flow_flush,
- dpif_netdev_flow_dump_start,
- dpif_netdev_flow_dump_next,
- dpif_netdev_flow_dump_done,
- dpif_netdev_execute,
- NULL, /* operate */
- dpif_netdev_recv_set,
- dpif_netdev_queue_to_priority,
- dpif_netdev_recv,
- dpif_netdev_recv_wait,
- dpif_netdev_recv_purge,
+ DPIF_NETDEV_CLASS_FUNCTIONS
+};
+
+const struct dpif_class dpif_planetlab_class = {
+ "planetlab",
+ DPIF_NETDEV_CLASS_FUNCTIONS
};
static void
dpif_dummy_register__("dummy");
}
+