#include "poll-loop.h"
#include "random.h"
#include "shash.h"
+#include "sset.h"
#include "timeval.h"
#include "util.h"
#include "vlog.h"
int port_no; /* Index into dp_netdev's 'ports'. */
struct list node; /* Element in dp_netdev's 'port_list'. */
struct netdev *netdev;
- bool internal; /* Internal port? */
+ char *type; /* Port type as requested by user. */
};
/* A flow in dp_netdev's 'flow_table'. */
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;
struct dpif_netdev {
struct dpif dpif;
struct dp_netdev *dp;
- int listen_mask;
unsigned int dp_serial;
};
const struct nlattr *actions,
size_t actions_len);
-static struct dpif_class dpif_dummy_class;
-
static struct dpif_netdev *
dpif_netdev_cast(const struct dpif *dpif)
{
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)
{
dpif = xmalloc(sizeof *dpif);
dpif_init(&dpif->dpif, dp->class, dp->name, netflow_id >> 8, netflow_id);
dpif->dp = dp;
- dpif->listen_mask = 0;
dpif->dp_serial = dp->serial;
return &dpif->dpif;
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 "tap_pl";
+ return "dummy";
+}
+
static int
do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
uint16_t port_no)
{
struct dp_netdev_port *port;
struct netdev *netdev;
- bool internal;
+ const char *open_type;
int mtu;
int error;
/* XXX reject devices already in some dp_netdev. */
- if (type[0] == '\0' || !strcmp(type, "system") || !strcmp(type, "dummy")) {
- internal = false;
- } else if (!strcmp(type, "internal")) {
- internal = true;
- } else {
- VLOG_WARN("%s: unsupported port type %s", devname, type);
- return EINVAL;
- }
/* Open and validate network device. */
- if (dp->class == &dpif_dummy_class) {
- type = "dummy";
- } else if (internal) {
- type = "tap";
- }
-
- error = netdev_open(devname, type, &netdev);
+ open_type = (strcmp(type, "internal") ? type : internal_port_type(dp));
+ error = netdev_open(devname, open_type, &netdev);
if (error) {
return error;
}
port = xmalloc(sizeof *port);
port->port_no = port_no;
port->netdev = netdev;
- port->internal = internal;
+ port->type = xstrdup(type);
error = netdev_get_mtu(netdev, &mtu);
if (!error) {
struct dp_netdev *dp = get_dp_netdev(dpif);
int port_no;
- if (dpif->dpif_class == &dpif_dummy_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. */
name = xstrdup(netdev_get_name(port->netdev));
netdev_close(port->netdev);
+ free(port->type);
free(name);
free(port);
struct dpif_port *dpif_port)
{
dpif_port->name = xstrdup(netdev_get_name(port->netdev));
- dpif_port->type = xstrdup(port->internal ? "internal"
- : netdev_get_type(port->netdev));
+ dpif_port->type = xstrdup(port->type);
dpif_port->port_no = port->port_no;
}
free(state->name);
state->name = xstrdup(netdev_get_name(port->netdev));
dpif_port->name = state->name;
- dpif_port->type = (char *) (port->internal ? "internal"
- : netdev_get_type(port->netdev));
+ dpif_port->type = port->type;
dpif_port->port_no = port->port_no;
state->port_no = port_no + 1;
return 0;
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
flow->used = 0;
flow->packet_count = 0;
flow->byte_count = 0;
- flow->tcp_ctl = 0;
+ flow->tcp_flags = 0;
}
static int
-dpif_netdev_flow_put(struct dpif *dpif, enum dpif_flow_put_flags flags,
- const struct nlattr *nl_key, size_t nl_key_len,
- const struct nlattr *actions, size_t actions_len,
- struct dpif_flow_stats *stats)
+dpif_netdev_flow_put(struct dpif *dpif, const struct dpif_flow_put *put)
{
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(put->key, put->key_len, &key);
if (error) {
return error;
}
flow = dp_netdev_lookup_flow(dp, &key);
if (!flow) {
- if (flags & DPIF_FP_CREATE) {
+ if (put->flags & DPIF_FP_CREATE) {
if (hmap_count(&dp->flow_table) < MAX_FLOWS) {
- if (stats) {
- memset(stats, 0, sizeof *stats);
+ if (put->stats) {
+ memset(put->stats, 0, sizeof *put->stats);
}
- return add_flow(dpif, &key, actions, actions_len);
+ return add_flow(dpif, &key, put->actions, put->actions_len);
} else {
return EFBIG;
}
return ENOENT;
}
} else {
- if (flags & DPIF_FP_MODIFY) {
- int error = set_flow_actions(flow, actions, actions_len);
+ if (put->flags & DPIF_FP_MODIFY) {
+ int error = set_flow_actions(flow, put->actions, put->actions_len);
if (!error) {
- if (stats) {
- get_dpif_flow_stats(flow, stats);
+ if (put->stats) {
+ get_dpif_flow_stats(flow, put->stats);
}
- if (flags & DPIF_FP_ZERO_STATS) {
+ if (put->flags & DPIF_FP_ZERO_STATS) {
clear_stats(flow);
}
}
}
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_execute(struct dpif *dpif,
- const struct nlattr *key_attrs, size_t key_len,
- const struct nlattr *actions, size_t actions_len,
- const struct ofpbuf *packet)
+dpif_netdev_execute(struct dpif *dpif, const struct dpif_execute *execute)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
struct ofpbuf copy;
struct flow key;
int error;
- if (packet->size < ETH_HEADER_LEN || packet->size > UINT16_MAX) {
+ if (execute->packet->size < ETH_HEADER_LEN ||
+ execute->packet->size > UINT16_MAX) {
return EINVAL;
}
/* Make a deep copy of 'packet', because we might modify its data. */
- ofpbuf_init(©, DP_NETDEV_HEADROOM + packet->size);
+ ofpbuf_init(©, DP_NETDEV_HEADROOM + execute->packet->size);
ofpbuf_reserve(©, DP_NETDEV_HEADROOM);
- ofpbuf_put(©, packet->data, packet->size);
+ ofpbuf_put(©, execute->packet->data, execute->packet->size);
flow_extract(©, 0, 0, -1, &key);
- error = dpif_netdev_flow_from_nlattrs(key_attrs, key_len, &key);
+ error = dpif_netdev_flow_from_nlattrs(execute->key, execute->key_len,
+ &key);
if (!error) {
dp_netdev_execute_actions(dp, ©, &key,
- actions, actions_len);
+ execute->actions, execute->actions_len);
}
ofpbuf_uninit(©);
}
static int
-dpif_netdev_recv_get_mask(const struct dpif *dpif, int *listen_mask)
+dpif_netdev_recv_set(struct dpif *dpif OVS_UNUSED, bool enable OVS_UNUSED)
{
- struct dpif_netdev *dpif_netdev = dpif_netdev_cast(dpif);
- *listen_mask = dpif_netdev->listen_mask;
- return 0;
-}
-
-static int
-dpif_netdev_recv_set_mask(struct dpif *dpif, int listen_mask)
-{
- struct dpif_netdev *dpif_netdev = dpif_netdev_cast(dpif);
- dpif_netdev->listen_mask = listen_mask;
return 0;
}
static struct dp_netdev_queue *
find_nonempty_queue(struct dpif *dpif)
{
- struct dpif_netdev *dpif_netdev = dpif_netdev_cast(dpif);
struct dp_netdev *dp = get_dp_netdev(dpif);
- int mask = dpif_netdev->listen_mask;
int i;
for (i = 0; i < N_QUEUES; i++) {
struct dp_netdev_queue *q = &dp->queues[i];
- if (q->head != q->tail && mask & (1u << i)) {
+ if (q->head != q->tail) {
return q;
}
}
}
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) {
*upcall = *u;
free(u);
+ ofpbuf_uninit(buf);
+ *buf = *u->packet;
+
return 0;
} else {
return EAGAIN;
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
}
}
+#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_get_mask,
- dpif_netdev_recv_set_mask,
- 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__(const char *type)
+{
+ struct dpif_class *class;
+
+ class = xmalloc(sizeof *class);
+ *class = dpif_netdev_class;
+ class->type = xstrdup(type);
+ dp_register_provider(class);
+}
+
void
-dpif_dummy_register(void)
+dpif_dummy_register(bool override)
{
- if (!dpif_dummy_class.type) {
- dpif_dummy_class = dpif_netdev_class;
- dpif_dummy_class.type = "dummy";
- dp_register_provider(&dpif_dummy_class);
+ if (override) {
+ struct sset types;
+ const char *type;
+
+ sset_init(&types);
+ dp_enumerate_types(&types);
+ SSET_FOR_EACH (type, &types) {
+ if (!dp_unregister_provider(type)) {
+ dpif_dummy_register__(type);
+ }
+ }
+ sset_destroy(&types);
}
+
+ dpif_dummy_register__("dummy");
}
+