diff options
Diffstat (limited to 'datapath')
-rw-r--r-- | datapath/actions.c | 35 | ||||
-rw-r--r-- | datapath/datapath.c | 17 | ||||
-rw-r--r-- | datapath/datapath.h | 60 |
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; |