aboutsummaryrefslogtreecommitdiff
path: root/datapath
diff options
context:
space:
mode:
Diffstat (limited to 'datapath')
-rw-r--r--datapath/actions.c35
-rw-r--r--datapath/datapath.c17
-rw-r--r--datapath/datapath.h60
3 files changed, 103 insertions, 9 deletions
diff --git a/datapath/actions.c b/datapath/actions.c
index cadab05f..8b32de47 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -1,6 +1,6 @@
/*
* Distributed under the terms of the GNU GPL version 2.
- * Copyright (c) 2007, 2008, 2009 Nicira Networks.
+ * Copyright (c) 2007, 2008, 2009, 2010 Nicira Networks.
*
* Significant portions of this file may be copied from parts of the Linux
* kernel, by Linus Torvalds and others.
@@ -366,6 +366,28 @@ output_control(struct datapath *dp, struct sk_buff *skb, u32 arg, gfp_t gfp)
return dp_output_control(dp, skb, _ODPL_ACTION_NR, arg);
}
+/* Send a copy of this packet up to the sFlow agent, along with extra
+ * information about what happened to it. */
+static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
+ const union odp_action *a, int n_actions,
+ gfp_t gfp, struct net_bridge_port *nbp)
+{
+ struct odp_sflow_sample_header *hdr;
+ unsigned int actlen = n_actions * sizeof(union odp_action);
+ unsigned int hdrlen = sizeof(struct odp_sflow_sample_header);
+ struct sk_buff *nskb;
+
+ nskb = skb_copy_expand(skb, actlen + hdrlen, 0, gfp);
+ if (!nskb)
+ return;
+
+ memcpy(__skb_push(nskb, actlen), a, actlen);
+ hdr = (struct odp_sflow_sample_header*)__skb_push(nskb, hdrlen);
+ hdr->n_actions = n_actions;
+ hdr->sample_pool = atomic_read(&nbp->sflow_pool);
+ dp_output_control(dp, nskb, _ODPL_SFLOW_NR, 0);
+}
+
/* Execute a list of actions against 'skb'. */
int execute_actions(struct datapath *dp, struct sk_buff *skb,
struct odp_flow_key *key,
@@ -378,6 +400,17 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
* is slightly obscure just to avoid that. */
int prev_port = -1;
int err;
+
+ if (dp->sflow_probability) {
+ struct net_bridge_port *p = skb->dev->br_port;
+ if (p) {
+ atomic_inc(&p->sflow_pool);
+ if (dp->sflow_probability == UINT_MAX ||
+ net_random() < dp->sflow_probability)
+ sflow_sample(dp, skb, a, n_actions, gfp, p);
+ }
+ }
+
for (; n_actions > 0; a++, n_actions--) {
WARN_ON_ONCE(skb_shared(skb));
if (prev_port != -1) {
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 12798958..ba363fb7 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2007, 2008, 2009 Nicira Networks.
+ * Copyright (c) 2007, 2008, 2009, 2010 Nicira Networks.
* Distributed under the terms of the GNU GPL version 2.
*
* Significant portions of this file may be copied from parts of the Linux
@@ -349,6 +349,7 @@ static int new_nbp(struct datapath *dp, struct net_device *dev, int port_no)
p->port_no = port_no;
p->dp = dp;
p->dev = dev;
+ atomic_set(&p->sflow_pool, 0);
if (!is_dp_dev(dev))
rcu_assign_pointer(dev->br_port, p);
else {
@@ -713,8 +714,7 @@ dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no,
int err;
WARN_ON_ONCE(skb_shared(skb));
- BUG_ON(queue_no != _ODPL_MISS_NR && queue_no != _ODPL_ACTION_NR);
-
+ BUG_ON(queue_no != _ODPL_MISS_NR && queue_no != _ODPL_ACTION_NR && queue_no != _ODPL_SFLOW_NR);
queue = &dp->queues[queue_no];
err = -ENOBUFS;
if (skb_queue_len(queue) >= DP_MAX_QUEUE_LEN)
@@ -1391,6 +1391,7 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
int dp_idx = iminor(f->f_dentry->d_inode);
struct datapath *dp;
int drop_frags, listeners, port_no;
+ unsigned int sflow_probability;
int err;
/* Handle commands with special locking requirements up front. */
@@ -1454,6 +1455,16 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
set_listen_mask(f, listeners);
break;
+ case ODP_GET_SFLOW_PROBABILITY:
+ err = put_user(dp->sflow_probability, (unsigned int __user *)argp);
+ break;
+
+ case ODP_SET_SFLOW_PROBABILITY:
+ err = get_user(sflow_probability, (unsigned int __user *)argp);
+ if (!err)
+ dp->sflow_probability = sflow_probability;
+ break;
+
case ODP_PORT_QUERY:
err = query_port(dp, (struct odp_port __user *)argp);
break;
diff --git a/datapath/datapath.h b/datapath/datapath.h
index 643c91ac..3b5a67b1 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2009 Nicira Networks.
+ * Copyright (c) 2009, 2010 Nicira Networks.
* Distributed under the terms of the GNU GPL version 2.
*
* Significant portions of this file may be copied from parts of the Linux
@@ -79,9 +79,22 @@ struct dp_bucket {
struct sw_flow *flows[];
};
-#define DP_N_QUEUES 2
+#define DP_N_QUEUES 3
#define DP_MAX_QUEUE_LEN 100
+/**
+ * struct dp_stats_percpu - per-cpu packet processing statistics for a given
+ * datapath.
+ * @n_frags: Number of IP fragments processed by datapath.
+ * @n_hit: Number of received packets for which a matching flow was found in
+ * the flow table.
+ * @n_miss: Number of received packets that had no matching flow in the flow
+ * table. The sum of @n_hit and @n_miss is the number of packets that have
+ * been received by the datapath.
+ * @n_lost: Number of received packets that had no matching flow in the flow
+ * table that could not be sent to userspace (normally due to an overflow in
+ * one of the datapath's queues).
+ */
struct dp_stats_percpu {
u64 n_frags;
u64 n_hit;
@@ -95,10 +108,29 @@ struct dp_port_group {
u16 ports[];
};
+/**
+ * struct datapath - datapath for flow-based packet switching
+ * @mutex: Mutual exclusion for ioctls.
+ * @dp_idx: Datapath number (index into the dps[] array in datapath.c).
+ * @ifobj: Represents /sys/class/net/<devname>/brif.
+ * @drop_frags: Drop all IP fragments if nonzero.
+ * @queues: %DP_N_QUEUES sets of queued packets for userspace to handle.
+ * @waitqueue: Waitqueue, for waiting for new packets in @queues.
+ * @n_flows: Number of flows currently in flow table.
+ * @table: Current flow table (RCU protected).
+ * @groups: Port groups, used by ODPAT_OUTPUT_GROUP action (RCU protected).
+ * @n_ports: Number of ports currently in @ports.
+ * @ports: Map from port number to &struct net_bridge_port. %ODPP_LOCAL port
+ * always exists, other ports may be %NULL.
+ * @port_list: List of all ports in @ports in arbitrary order.
+ * @stats_percpu: Per-CPU datapath statistics.
+ * @sflow_probability: Number of packets out of UINT_MAX to sample to the
+ * %ODPL_SFLOW queue, e.g. (@sflow_probability/UINT_MAX) is the probability of
+ * sampling a given packet.
+ */
struct datapath {
struct mutex mutex;
int dp_idx;
-
struct kobject ifobj;
int drop_frags;
@@ -117,19 +149,37 @@ struct datapath {
/* Switch ports. */
unsigned int n_ports;
struct net_bridge_port *ports[DP_MAX_PORTS];
- struct list_head port_list; /* All ports, including local_port. */
+ struct list_head port_list;
/* Stats. */
struct dp_stats_percpu *stats_percpu;
+
+ /* sFlow Sampling */
+ unsigned int sflow_probability;
};
+/**
+ * struct net_bridge_port - one port within a datapath
+ * @port_no: Index into @dp's @ports array.
+ * @dp: Datapath to which this port belongs.
+ * @dev: The network device attached to this port. The @br_port member in @dev
+ * points back to this &struct net_bridge_port.
+ * @kobj: Represents /sys/class/net/<devname>/brport.
+ * @linkname: The name of the link from /sys/class/net/<datapath>/brif to this
+ * &struct net_bridge_port. (We keep this around so that we can delete it
+ * if @dev gets renamed.) Set to the null string when no link exists.
+ * @node: Element in @dp's @port_list.
+ * @sflow_pool: Number of packets that were candidates for sFlow sampling,
+ * regardless of whether they were actually chosen and sent down to userspace.
+ */
struct net_bridge_port {
u16 port_no;
struct datapath *dp;
struct net_device *dev;
struct kobject kobj;
char linkname[IFNAMSIZ];
- struct list_head node; /* Element in datapath.ports. */
+ struct list_head node;
+ atomic_t sflow_pool;
};
extern struct notifier_block dp_device_notifier;