[ovs-dev] [netlink v3 3/5] datapath: Merge "struct dp_port" into "struct vport".

Ben Pfaff blp at nicira.com
Wed Nov 17 01:11:24 UTC 2010


After the previous commit, which changed the datapath to always create and
attach a vport at the same time, and to always detach and delete a vport
at the same time, there is no longer any real distinction between a dp_port
and a vport.  This commit, therefore, merges the two together to simplify
code.  It might even improve performance, although I have not checked.

I wasn't sure at first whether the merged structure should be "struct
dp_port" or "struct vport".  I went with the latter since the "v" prefix
sounds cool.

Signed-off-by: Ben Pfaff <blp at nicira.com>
---
 datapath/actions.c            |   10 ++--
 datapath/datapath.c           |  123 +++++++++++++++--------------------------
 datapath/datapath.h           |   37 ++----------
 datapath/dp_notify.c          |   15 ++---
 datapath/dp_sysfs.h           |    6 +-
 datapath/dp_sysfs_dp.c        |   19 ++-----
 datapath/dp_sysfs_if.c        |   58 ++++++++++----------
 datapath/tunnel.c             |   17 ++----
 datapath/vport-internal_dev.c |   19 ++-----
 datapath/vport-netdev.c       |    2 +-
 datapath/vport-patch.c        |   18 +++---
 datapath/vport.c              |  116 +++++++++++++-------------------------
 datapath/vport.h              |   41 ++++++++++++--
 13 files changed, 196 insertions(+), 285 deletions(-)

diff --git a/datapath/actions.c b/datapath/actions.c
index 5904c83..41812a4 100644
--- a/datapath/actions.c
+++ b/datapath/actions.c
@@ -368,7 +368,7 @@ static bool is_spoofed_arp(struct sk_buff *skb, const struct odp_flow_key *key)
 
 static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
 {
-	struct dp_port *p;
+	struct vport *p;
 
 	if (!skb)
 		goto error;
@@ -377,7 +377,7 @@ static void do_output(struct datapath *dp, struct sk_buff *skb, int out_port)
 	if (!p)
 		goto error;
 
-	vport_send(p->vport, skb);
+	vport_send(p, skb);
 	return;
 
 error:
@@ -396,7 +396,7 @@ static int output_control(struct datapath *dp, struct sk_buff *skb, u32 arg)
  * 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,
-			 struct dp_port *dp_port)
+			 struct vport *vport)
 {
 	struct odp_sflow_sample_header *hdr;
 	unsigned int actlen = n_actions * sizeof(union odp_action);
@@ -410,7 +410,7 @@ static void sflow_sample(struct datapath *dp, struct sk_buff *skb,
 	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(&dp_port->sflow_pool);
+	hdr->sample_pool = atomic_read(&vport->sflow_pool);
 	dp_output_control(dp, nskb, _ODPL_SFLOW_NR, 0);
 }
 
@@ -428,7 +428,7 @@ int execute_actions(struct datapath *dp, struct sk_buff *skb,
 	int err;
 
 	if (dp->sflow_probability) {
-		struct dp_port *p = OVS_CB(skb)->dp_port;
+		struct vport *p = OVS_CB(skb)->vport;
 		if (p) {
 			atomic_inc(&p->sflow_pool);
 			if (dp->sflow_probability == UINT_MAX ||
diff --git a/datapath/datapath.c b/datapath/datapath.c
index 0f2fb80..a3e7872 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -64,13 +64,13 @@ EXPORT_SYMBOL(dp_ioctl_hook);
  * dp_mutex nests inside the RTNL lock: if you need both you must take the RTNL
  * lock first.
  *
- * It is safe to access the datapath and dp_port structures with just
+ * It is safe to access the datapath and vport structures with just
  * dp_mutex.
  */
 static struct datapath *dps[ODP_MAX];
 static DEFINE_MUTEX(dp_mutex);
 
-static int new_dp_port(struct datapath *, struct odp_port *, int port_no);
+static int new_vport(struct datapath *, struct odp_port *, int port_no);
 
 /* Must be called with rcu_read_lock or dp_mutex. */
 struct datapath *get_dp(int dp_idx)
@@ -96,7 +96,7 @@ static struct datapath *get_dp_locked(int dp_idx)
 /* Must be called with rcu_read_lock or RTNL lock. */
 const char *dp_name(const struct datapath *dp)
 {
-	return vport_get_name(dp->ports[ODPP_LOCAL]->vport);
+	return vport_get_name(dp->ports[ODPP_LOCAL]);
 }
 
 static inline size_t br_nlmsg_size(void)
@@ -111,12 +111,12 @@ static inline size_t br_nlmsg_size(void)
 }
 
 static int dp_fill_ifinfo(struct sk_buff *skb,
-			  const struct dp_port *port,
+			  const struct vport *port,
 			  int event, unsigned int flags)
 {
 	const struct datapath *dp = port->dp;
-	int ifindex = vport_get_ifindex(port->vport);
-	int iflink = vport_get_iflink(port->vport);
+	int ifindex = vport_get_ifindex(port);
+	int iflink = vport_get_iflink(port);
 	struct ifinfomsg *hdr;
 	struct nlmsghdr *nlh;
 
@@ -135,21 +135,20 @@ static int dp_fill_ifinfo(struct sk_buff *skb,
 	hdr->__ifi_pad = 0;
 	hdr->ifi_type = ARPHRD_ETHER;
 	hdr->ifi_index = ifindex;
-	hdr->ifi_flags = vport_get_flags(port->vport);
+	hdr->ifi_flags = vport_get_flags(port);
 	hdr->ifi_change = 0;
 
-	NLA_PUT_STRING(skb, IFLA_IFNAME, vport_get_name(port->vport));
-	NLA_PUT_U32(skb, IFLA_MASTER, vport_get_ifindex(dp->ports[ODPP_LOCAL]->vport));
-	NLA_PUT_U32(skb, IFLA_MTU, vport_get_mtu(port->vport));
+	NLA_PUT_STRING(skb, IFLA_IFNAME, vport_get_name(port));
+	NLA_PUT_U32(skb, IFLA_MASTER, vport_get_ifindex(dp->ports[ODPP_LOCAL]));
+	NLA_PUT_U32(skb, IFLA_MTU, vport_get_mtu(port));
 #ifdef IFLA_OPERSTATE
 	NLA_PUT_U8(skb, IFLA_OPERSTATE,
-		   vport_is_running(port->vport)
-			? vport_get_operstate(port->vport)
+		   vport_is_running(port)
+			? vport_get_operstate(port)
 			: IF_OPER_DOWN);
 #endif
 
-	NLA_PUT(skb, IFLA_ADDRESS, ETH_ALEN,
-					vport_get_addr(port->vport));
+	NLA_PUT(skb, IFLA_ADDRESS, ETH_ALEN, vport_get_addr(port));
 
 	if (ifindex != iflink)
 		NLA_PUT_U32(skb, IFLA_LINK,iflink);
@@ -161,7 +160,7 @@ nla_put_failure:
 	return -EMSGSIZE;
 }
 
-static void dp_ifinfo_notify(int event, struct dp_port *port)
+static void dp_ifinfo_notify(int event, struct vport *port)
 {
 	struct sk_buff *skb;
 	int err = -ENOBUFS;
@@ -254,7 +253,7 @@ static int create_dp(int dp_idx, const char __user *devnamep)
 	BUILD_BUG_ON(sizeof(internal_dev_port.devname) != sizeof(devname));
 	strcpy(internal_dev_port.devname, devname);
 	strcpy(internal_dev_port.type, "internal");
-	err = new_dp_port(dp, &internal_dev_port, ODPP_LOCAL);
+	err = new_vport(dp, &internal_dev_port, ODPP_LOCAL);
 	if (err) {
 		if (err == -EBUSY)
 			err = -EEXIST;
@@ -292,7 +291,7 @@ err:
 
 static void do_destroy_dp(struct datapath *dp)
 {
-	struct dp_port *p, *n;
+	struct vport *p, *n;
 	int i;
 
 	list_for_each_entry_safe (p, n, &dp->port_list, node)
@@ -335,30 +334,18 @@ err_unlock:
 	return err;
 }
 
-static void release_dp_port(struct kobject *kobj)
-{
-	struct dp_port *p = container_of(kobj, struct dp_port, kobj);
-	kfree(p);
-}
-
-static struct kobj_type brport_ktype = {
-#ifdef CONFIG_SYSFS
-	.sysfs_ops = &brport_sysfs_ops,
-#endif
-	.release = release_dp_port
-};
-
 /* Called with RTNL lock and dp_mutex. */
-static int new_dp_port(struct datapath *dp, struct odp_port *odp_port, int port_no)
+static int new_vport(struct datapath *dp, struct odp_port *odp_port, int port_no)
 {
 	struct vport_parms parms;
 	struct vport *vport;
-	struct dp_port *p;
 	int err;
 
 	parms.name = odp_port->devname;
 	parms.type = odp_port->type;
 	parms.config = odp_port->config;
+	parms.dp = dp;
+	parms.port_no = port_no;
 
 	vport_lock();
 	vport = vport_add(&parms);
@@ -367,31 +354,17 @@ static int new_dp_port(struct datapath *dp, struct odp_port *odp_port, int port_
 	if (IS_ERR(vport))
 		return PTR_ERR(vport);
 
-	p = kzalloc(sizeof(*p), GFP_KERNEL);
-	if (!p)
-		return -ENOMEM;
-
-	p->port_no = port_no;
-	p->dp = dp;
-	p->vport = vport;
-	atomic_set(&p->sflow_pool, 0);
-
-	err = vport_attach(vport, p);
+	err = vport_attach(vport);
 	if (err) {
-		kfree(p);
+		vport_del(vport);
 		return err;
 	}
 
-	rcu_assign_pointer(dp->ports[port_no], p);
-	list_add_rcu(&p->node, &dp->port_list);
+	rcu_assign_pointer(dp->ports[port_no], vport);
+	list_add_rcu(&vport->node, &dp->port_list);
 	dp->n_ports++;
 
-	/* Initialize kobject for bridge.  This will be added as
-	 * /sys/class/net/<devname>/brport later, if sysfs is enabled. */
-	p->kobj.kset = NULL;
-	kobject_init(&p->kobj, &brport_ktype);
-
-	dp_ifinfo_notify(RTM_NEWLINK, p);
+	dp_ifinfo_notify(RTM_NEWLINK, vport);
 
 	return 0;
 }
@@ -422,7 +395,7 @@ static int attach_port(int dp_idx, struct odp_port __user *portp)
 	goto out_unlock_dp;
 
 got_port_no:
-	err = new_dp_port(dp, &port, port_no);
+	err = new_vport(dp, &port, port_no);
 	if (err)
 		goto out_unlock_dp;
 
@@ -439,9 +412,8 @@ out:
 	return err;
 }
 
-int dp_detach_port(struct dp_port *p)
+int dp_detach_port(struct vport *p)
 {
-	struct vport *vport = p->vport;
 	int err;
 
 	ASSERT_RTNL();
@@ -455,7 +427,7 @@ int dp_detach_port(struct dp_port *p)
 	list_del_rcu(&p->node);
 	rcu_assign_pointer(p->dp->ports[p->port_no], NULL);
 
-	err = vport_detach(vport);
+	err = vport_detach(p);
 	if (err)
 		return err;
 
@@ -463,17 +435,15 @@ int dp_detach_port(struct dp_port *p)
 	synchronize_rcu();
 
 	vport_lock();
-	vport_del(vport);
+	vport_del(p);
 	vport_unlock();
 
-	kobject_put(&p->kobj);
-
 	return 0;
 }
 
 static int detach_port(int dp_idx, int port_no)
 {
-	struct dp_port *p;
+	struct vport *p;
 	struct datapath *dp;
 	int err;
 
@@ -503,7 +473,7 @@ out:
 }
 
 /* Must be called with rcu_read_lock. */
-void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
+void dp_process_received_packet(struct vport *p, struct sk_buff *skb)
 {
 	struct datapath *dp = p->dp;
 	struct dp_stats_percpu *stats;
@@ -512,7 +482,7 @@ void dp_process_received_packet(struct dp_port *p, struct sk_buff *skb)
 	struct loop_counter *loop;
 	int error;
 
-	OVS_CB(skb)->dp_port = p;
+	OVS_CB(skb)->vport = p;
 
 	if (!OVS_CB(skb)->flow) {
 		struct odp_flow_key key;
@@ -758,8 +728,8 @@ static int queue_control_packets(struct sk_buff *skb, struct sk_buff_head *queue
 	int port_no;
 	int err;
 
-	if (OVS_CB(skb)->dp_port)
-		port_no = OVS_CB(skb)->dp_port->port_no;
+	if (OVS_CB(skb)->vport)
+		port_no = OVS_CB(skb)->vport->port_no;
 	else
 		port_no = ODPP_LOCAL;
 
@@ -1383,7 +1353,7 @@ static int get_dp_stats(struct datapath *dp, struct odp_stats __user *statsp)
 /* MTU of the dp pseudo-device: ETH_DATA_LEN or the minimum of the ports */
 int dp_min_mtu(const struct datapath *dp)
 {
-	struct dp_port *p;
+	struct vport *p;
 	int mtu = 0;
 
 	ASSERT_RTNL();
@@ -1393,10 +1363,10 @@ int dp_min_mtu(const struct datapath *dp)
 
 		/* Skip any internal ports, since that's what we're trying to
 		 * set. */
-		if (is_internal_vport(p->vport))
+		if (is_internal_vport(p))
 			continue;
 
-		dev_mtu = vport_get_mtu(p->vport);
+		dev_mtu = vport_get_mtu(p);
 		if (!mtu || dev_mtu < mtu)
 			mtu = dev_mtu;
 	}
@@ -1408,7 +1378,7 @@ int dp_min_mtu(const struct datapath *dp)
  * be called with RTNL lock. */
 void set_internal_devs_mtu(const struct datapath *dp)
 {
-	struct dp_port *p;
+	struct vport *p;
 	int mtu;
 
 	ASSERT_RTNL();
@@ -1416,20 +1386,20 @@ void set_internal_devs_mtu(const struct datapath *dp)
 	mtu = dp_min_mtu(dp);
 
 	list_for_each_entry_rcu (p, &dp->port_list, node) {
-		if (is_internal_vport(p->vport))
-			vport_set_mtu(p->vport, mtu);
+		if (is_internal_vport(p))
+			vport_set_mtu(p, mtu);
 	}
 }
 
-static int put_port(const struct dp_port *p, struct odp_port __user *uop)
+static int put_port(const struct vport *p, struct odp_port __user *uop)
 {
 	struct odp_port op;
 
 	memset(&op, 0, sizeof op);
 
 	rcu_read_lock();
-	strncpy(op.devname, vport_get_name(p->vport), sizeof op.devname);
-	strncpy(op.type, vport_get_type(p->vport), sizeof op.type);
+	strncpy(op.devname, vport_get_name(p), sizeof op.devname);
+	strncpy(op.type, vport_get_type(p), sizeof op.type);
 	rcu_read_unlock();
 
 	op.port = p->port_no;
@@ -1446,7 +1416,6 @@ static int query_port(struct datapath *dp, struct odp_port __user *uport)
 
 	if (port.devname[0]) {
 		struct vport *vport;
-		struct dp_port *dp_port;
 		int err = 0;
 
 		port.devname[IFNAMSIZ - 1] = '\0';
@@ -1459,14 +1428,12 @@ static int query_port(struct datapath *dp, struct odp_port __user *uport)
 			err = -ENODEV;
 			goto error_unlock;
 		}
-
-		dp_port = vport_get_dp_port(vport);
-		if (!dp_port || dp_port->dp != dp) {
+		if (vport->dp != dp) {
 			err = -ENOENT;
 			goto error_unlock;
 		}
 
-		port.port = dp_port->port_no;
+		port.port = vport->port_no;
 
 error_unlock:
 		rcu_read_unlock();
@@ -1489,7 +1456,7 @@ static int do_list_ports(struct datapath *dp, struct odp_port __user *uports,
 {
 	int idx = 0;
 	if (n_ports) {
-		struct dp_port *p;
+		struct vport *p;
 
 		list_for_each_entry_rcu (p, &dp->port_list, node) {
 			if (put_port(p, &uports[idx]))
diff --git a/datapath/datapath.h b/datapath/datapath.h
index 36accfd..07406da 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -23,7 +23,6 @@
 #include "dp_sysfs.h"
 
 struct vport;
-struct dp_port;
 
 /* Mask for the priority bits in a vlan header.  If we ever merge upstream
  * then this should go into include/linux/if_vlan.h. */
@@ -67,7 +66,7 @@ struct dp_stats_percpu {
  * @n_flows: Number of flows currently in flow table.
  * @table: Current flow table (RCU protected).
  * @n_ports: Number of ports currently in @ports.
- * @ports: Map from port number to &struct dp_port.  %ODPP_LOCAL port
+ * @ports: Map from port number to &struct vport.  %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.
@@ -91,7 +90,7 @@ struct datapath {
 
 	/* Switch ports. */
 	unsigned int n_ports;
-	struct dp_port *ports[DP_MAX_PORTS];
+	struct vport *ports[DP_MAX_PORTS];
 	struct list_head port_list;
 
 	/* Stats. */
@@ -101,30 +100,6 @@ struct datapath {
 	unsigned int sflow_probability;
 };
 
-/**
- * struct dp_port - one port within a datapath
- * @port_no: Index into @dp's @ports array.
- * @dp: Datapath to which this port belongs.
- * @vport: The network device attached to this port.  The contents depends on
- * the device and should be accessed only through the vport_* functions.
- * @kobj: Represents /sys/class/net/<devname>/brport.
- * @linkname: The name of the link from /sys/class/net/<datapath>/brif to this
- * &struct dp_port.  (We keep this around so that we can delete it if the
- * device 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 dp_port {
-	u16 port_no;
-	struct datapath	*dp;
-	struct vport *vport;
-	struct kobject kobj;
-	char linkname[IFNAMSIZ];
-	struct list_head node;
-	atomic_t sflow_pool;
-};
-
 enum csum_type {
 	OVS_CSUM_NONE = 0,
 	OVS_CSUM_UNNECESSARY = 1,
@@ -134,7 +109,7 @@ enum csum_type {
 
 /**
  * struct ovs_skb_cb - OVS data in skb CB
- * @dp_port: The datapath port on which the skb entered the switch.
+ * @vport: The datapath port on which the skb entered the switch.
  * @flow: The flow associated with this packet.  May be %NULL if no flow.
  * @ip_summed: Consistently stores L4 checksumming status across different
  * kernel versions.
@@ -142,7 +117,7 @@ enum csum_type {
  * packet. It is 0 if the packet was not received on a tunnel.
  */
 struct ovs_skb_cb {
-	struct dp_port		*dp_port;
+	struct vport		*vport;
 	struct sw_flow		*flow;
 	enum csum_type		ip_summed;
 	__be32			tun_id;
@@ -152,8 +127,8 @@ struct ovs_skb_cb {
 extern struct notifier_block dp_device_notifier;
 extern int (*dp_ioctl_hook)(struct net_device *dev, struct ifreq *rq, int cmd);
 
-void dp_process_received_packet(struct dp_port *, struct sk_buff *);
-int dp_detach_port(struct dp_port *);
+void dp_process_received_packet(struct vport *, struct sk_buff *);
+int dp_detach_port(struct vport *);
 int dp_output_control(struct datapath *, struct sk_buff *, int, u32 arg);
 int dp_min_mtu(const struct datapath *dp);
 void set_internal_devs_mtu(const struct datapath *dp);
diff --git a/datapath/dp_notify.c b/datapath/dp_notify.c
index 1843d75..e7d08bc 100644
--- a/datapath/dp_notify.c
+++ b/datapath/dp_notify.c
@@ -19,7 +19,6 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
 {
 	struct net_device *dev = ptr;
 	struct vport *vport;
-	struct dp_port *p;
 	struct datapath *dp;
 
 	if (is_internal_dev(dev))
@@ -30,24 +29,20 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
 	if (!vport)
 		return NOTIFY_DONE;
 
-	p = vport_get_dp_port(vport);
-
-	if (!p)
-		return NOTIFY_DONE;
-	dp = p->dp;
+	dp = vport->dp;
 
 	switch (event) {
 	case NETDEV_UNREGISTER:
 		mutex_lock(&dp->mutex);
-		dp_detach_port(p);
+		dp_detach_port(vport);
 		mutex_unlock(&dp->mutex);
 		break;
 
 	case NETDEV_CHANGENAME:
-		if (p->port_no != ODPP_LOCAL) {
+		if (vport->port_no != ODPP_LOCAL) {
 			mutex_lock(&dp->mutex);
-			dp_sysfs_del_if(p);
-			dp_sysfs_add_if(p);
+			dp_sysfs_del_if(vport);
+			dp_sysfs_add_if(vport);
 			mutex_unlock(&dp->mutex);
 		}
 		break;
diff --git a/datapath/dp_sysfs.h b/datapath/dp_sysfs.h
index 2d688ac..49af58a 100644
--- a/datapath/dp_sysfs.h
+++ b/datapath/dp_sysfs.h
@@ -10,15 +10,15 @@
 #define DP_SYSFS_H 1
 
 struct datapath;
-struct dp_port;
+struct vport;
 
 /* dp_sysfs_dp.c */
 int dp_sysfs_add_dp(struct datapath *dp);
 int dp_sysfs_del_dp(struct datapath *dp);
 
 /* dp_sysfs_if.c */
-int dp_sysfs_add_if(struct dp_port *p);
-int dp_sysfs_del_if(struct dp_port *p);
+int dp_sysfs_add_if(struct vport *p);
+int dp_sysfs_del_if(struct vport *p);
 
 #ifdef CONFIG_SYSFS
 extern struct sysfs_ops brport_sysfs_ops;
diff --git a/datapath/dp_sysfs_dp.c b/datapath/dp_sysfs_dp.c
index 4abe4fb..413dfc3 100644
--- a/datapath/dp_sysfs_dp.c
+++ b/datapath/dp_sysfs_dp.c
@@ -46,16 +46,7 @@
 struct datapath *sysfs_get_dp(struct net_device *netdev)
 {
 	struct vport *vport = internal_dev_get_vport(netdev);
-	struct dp_port *dp_port;
-
-	if (!vport)
-		return NULL;
-
-	dp_port = vport_get_dp_port(vport);
-	if (!dp_port)
-		return NULL;
-
-	return dp_port->dp;
+	return vport ? vport->dp : NULL;
 }
 /*
  * Common code for storing bridge parameters.
@@ -359,7 +350,7 @@ static struct attribute_group bridge_group = {
  */
 int dp_sysfs_add_dp(struct datapath *dp)
 {
-	struct kobject *kobj = vport_get_kobj(dp->ports[ODPP_LOCAL]->vport);
+	struct kobject *kobj = vport_get_kobj(dp->ports[ODPP_LOCAL]);
 	int err;
 
 	/* Create /sys/class/net/<devname>/bridge directory. */
@@ -388,7 +379,7 @@ int dp_sysfs_add_dp(struct datapath *dp)
 
 int dp_sysfs_del_dp(struct datapath *dp)
 {
-	struct kobject *kobj = vport_get_kobj(dp->ports[ODPP_LOCAL]->vport);
+	struct kobject *kobj = vport_get_kobj(dp->ports[ODPP_LOCAL]);
 
 	kobject_del(&dp->ifobj);
 	sysfs_remove_group(kobj, &bridge_group);
@@ -398,6 +389,6 @@ int dp_sysfs_del_dp(struct datapath *dp)
 #else /* !CONFIG_SYSFS */
 int dp_sysfs_add_dp(struct datapath *dp) { return 0; }
 int dp_sysfs_del_dp(struct datapath *dp) { return 0; }
-int dp_sysfs_add_if(struct dp_port *p) { return 0; }
-int dp_sysfs_del_if(struct dp_port *p) { return 0; }
+int dp_sysfs_add_if(struct vport *p) { return 0; }
+int dp_sysfs_del_if(struct vport *p) { return 0; }
 #endif /* !CONFIG_SYSFS */
diff --git a/datapath/dp_sysfs_if.c b/datapath/dp_sysfs_if.c
index b40523a..fc7c2d8 100644
--- a/datapath/dp_sysfs_if.c
+++ b/datapath/dp_sysfs_if.c
@@ -26,8 +26,8 @@
 
 struct brport_attribute {
 	struct attribute	attr;
-	ssize_t (*show)(struct dp_port *, char *);
-	ssize_t (*store)(struct dp_port *, unsigned long);
+	ssize_t (*show)(struct vport *, char *);
+	ssize_t (*store)(struct vport *, unsigned long);
 };
 
 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,36)
@@ -49,98 +49,98 @@ struct brport_attribute brport_attr_##_name = { 	        \
 };
 #endif
 
-static ssize_t show_path_cost(struct dp_port *p, char *buf)
+static ssize_t show_path_cost(struct vport *p, char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
 }
-static ssize_t store_path_cost(struct dp_port *p, unsigned long v)
+static ssize_t store_path_cost(struct vport *p, unsigned long v)
 {
 	return 0;
 }
 static BRPORT_ATTR(path_cost, S_IRUGO | S_IWUSR,
 		   show_path_cost, store_path_cost);
 
-static ssize_t show_priority(struct dp_port *p, char *buf)
+static ssize_t show_priority(struct vport *p, char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
 }
-static ssize_t store_priority(struct dp_port *p, unsigned long v)
+static ssize_t store_priority(struct vport *p, unsigned long v)
 {
 	return 0;
 }
 static BRPORT_ATTR(priority, S_IRUGO | S_IWUSR,
 			 show_priority, store_priority);
 
-static ssize_t show_designated_root(struct dp_port *p, char *buf)
+static ssize_t show_designated_root(struct vport *p, char *buf)
 {
 	return sprintf(buf, "0000.010203040506\n");
 }
 static BRPORT_ATTR(designated_root, S_IRUGO, show_designated_root, NULL);
 
-static ssize_t show_designated_bridge(struct dp_port *p, char *buf)
+static ssize_t show_designated_bridge(struct vport *p, char *buf)
 {
 	return sprintf(buf, "0000.060504030201\n");
 }
 static BRPORT_ATTR(designated_bridge, S_IRUGO, show_designated_bridge, NULL);
 
-static ssize_t show_designated_port(struct dp_port *p, char *buf)
+static ssize_t show_designated_port(struct vport *p, char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
 }
 static BRPORT_ATTR(designated_port, S_IRUGO, show_designated_port, NULL);
 
-static ssize_t show_designated_cost(struct dp_port *p, char *buf)
+static ssize_t show_designated_cost(struct vport *p, char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
 }
 static BRPORT_ATTR(designated_cost, S_IRUGO, show_designated_cost, NULL);
 
-static ssize_t show_port_id(struct dp_port *p, char *buf)
+static ssize_t show_port_id(struct vport *p, char *buf)
 {
 	return sprintf(buf, "0x%x\n", 0);
 }
 static BRPORT_ATTR(port_id, S_IRUGO, show_port_id, NULL);
 
-static ssize_t show_port_no(struct dp_port *p, char *buf)
+static ssize_t show_port_no(struct vport *p, char *buf)
 {
 	return sprintf(buf, "0x%x\n", p->port_no);
 }
 
 static BRPORT_ATTR(port_no, S_IRUGO, show_port_no, NULL);
 
-static ssize_t show_change_ack(struct dp_port *p, char *buf)
+static ssize_t show_change_ack(struct vport *p, char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
 }
 static BRPORT_ATTR(change_ack, S_IRUGO, show_change_ack, NULL);
 
-static ssize_t show_config_pending(struct dp_port *p, char *buf)
+static ssize_t show_config_pending(struct vport *p, char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
 }
 static BRPORT_ATTR(config_pending, S_IRUGO, show_config_pending, NULL);
 
-static ssize_t show_port_state(struct dp_port *p, char *buf)
+static ssize_t show_port_state(struct vport *p, char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
 }
 static BRPORT_ATTR(state, S_IRUGO, show_port_state, NULL);
 
-static ssize_t show_message_age_timer(struct dp_port *p,
+static ssize_t show_message_age_timer(struct vport *p,
 					    char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
 }
 static BRPORT_ATTR(message_age_timer, S_IRUGO, show_message_age_timer, NULL);
 
-static ssize_t show_forward_delay_timer(struct dp_port *p,
+static ssize_t show_forward_delay_timer(struct vport *p,
 					    char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
 }
 static BRPORT_ATTR(forward_delay_timer, S_IRUGO, show_forward_delay_timer, NULL);
 
-static ssize_t show_hold_timer(struct dp_port *p,
+static ssize_t show_hold_timer(struct vport *p,
 					    char *buf)
 {
 	return sprintf(buf, "%d\n", 0);
@@ -165,14 +165,14 @@ static struct brport_attribute *brport_attrs[] = {
 	NULL
 };
 
-#define to_brport_attr(_at) container_of(_at, struct brport_attribute, attr)
-#define to_brport(obj)	container_of(obj, struct dp_port, kobj)
+#define to_vport_attr(_at) container_of(_at, struct brport_attribute, attr)
+#define to_vport(obj)	container_of(obj, struct vport, kobj)
 
 static ssize_t brport_show(struct kobject * kobj,
 			   struct attribute * attr, char * buf)
 {
-	struct brport_attribute * brport_attr = to_brport_attr(attr);
-	struct dp_port * p = to_brport(kobj);
+	struct brport_attribute * brport_attr = to_vport_attr(attr);
+	struct vport * p = to_vport(kobj);
 
 	return brport_attr->show(p, buf);
 }
@@ -181,7 +181,7 @@ static ssize_t brport_store(struct kobject * kobj,
 			    struct attribute * attr,
 			    const char * buf, size_t count)
 {
-	struct dp_port * p = to_brport(kobj);
+	struct vport * p = to_vport(kobj);
 	ssize_t ret = -EINVAL;
 
 	if (!capable(CAP_NET_ADMIN))
@@ -203,9 +203,9 @@ struct sysfs_ops brport_sysfs_ops = {
  * Creates a brport subdirectory with bridge attributes.
  * Puts symlink in bridge's brport subdirectory
  */
-int dp_sysfs_add_if(struct dp_port *p)
+int dp_sysfs_add_if(struct vport *p)
 {
-	struct kobject *kobj = vport_get_kobj(p->vport);
+	struct kobject *kobj = vport_get_kobj(p);
 	struct datapath *dp = p->dp;
 	struct brport_attribute **a;
 	int err;
@@ -220,7 +220,7 @@ int dp_sysfs_add_if(struct dp_port *p)
 
 	/* Create symlink from /sys/class/net/<devname>/brport/bridge to
 	 * /sys/class/net/<bridgename>. */
-	err = sysfs_create_link(&p->kobj, vport_get_kobj(dp->ports[ODPP_LOCAL]->vport),
+	err = sysfs_create_link(&p->kobj, vport_get_kobj(dp->ports[ODPP_LOCAL]),
 				SYSFS_BRIDGE_PORT_LINK); /* "bridge" */
 	if (err)
 		goto err_del;
@@ -234,10 +234,10 @@ int dp_sysfs_add_if(struct dp_port *p)
 
 	/* Create symlink from /sys/class/net/<bridgename>/brif/<devname> to
 	 * /sys/class/net/<devname>/brport.  */
-	err = sysfs_create_link(&dp->ifobj, &p->kobj, vport_get_name(p->vport));
+	err = sysfs_create_link(&dp->ifobj, &p->kobj, vport_get_name(p));
 	if (err)
 		goto err_del;
-	strcpy(p->linkname, vport_get_name(p->vport));
+	strcpy(p->linkname, vport_get_name(p));
 
 	kobject_uevent(&p->kobj, KOBJ_ADD);
 
@@ -250,7 +250,7 @@ err:
 	return err;
 }
 
-int dp_sysfs_del_if(struct dp_port *p)
+int dp_sysfs_del_if(struct vport *p)
 {
 	if (p->linkname[0]) {
 		sysfs_remove_link(&p->dp->ifobj, p->linkname);
diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 15a8daa..3366ca4 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -887,22 +887,17 @@ static struct tnl_cache *build_cache(struct vport *vport,
 #endif
 
 	if (is_internal_dev(rt_dst(rt).dev)) {
-		int err;
+		struct odp_flow_key flow_key;
+		struct tbl_node *flow_node;
 		struct vport *vport;
-		struct dp_port *dp_port;
 		struct sk_buff *skb;
 		bool is_frag;
-		struct odp_flow_key flow_key;
-		struct tbl_node *flow_node;
+		int err;
 
 		vport = internal_dev_get_vport(rt_dst(rt).dev);
 		if (!vport)
 			goto done;
 
-		dp_port = vport_get_dp_port(vport);
-		if (!dp_port)
-			goto done;
-
 		skb = alloc_skb(cache->len, GFP_ATOMIC);
 		if (!skb)
 			goto done;
@@ -910,13 +905,13 @@ static struct tnl_cache *build_cache(struct vport *vport,
 		__skb_put(skb, cache->len);
 		memcpy(skb->data, get_cached_header(cache), cache->len);
 
-		err = flow_extract(skb, dp_port->port_no, &flow_key, &is_frag);
+		err = flow_extract(skb, vport->port_no, &flow_key, &is_frag);
 
 		kfree_skb(skb);
 		if (err || is_frag)
 			goto done;
 
-		flow_node = tbl_lookup(rcu_dereference(dp_port->dp->table),
+		flow_node = tbl_lookup(rcu_dereference(vport->dp->table),
 				       &flow_key, flow_hash(&flow_key),
 				       flow_cmp);
 		if (flow_node) {
@@ -1359,7 +1354,7 @@ struct vport *tnl_create(const struct vport_parms *parms,
 	int initial_frag_id;
 	int err;
 
-	vport = vport_alloc(sizeof(struct tnl_vport), vport_ops);
+	vport = vport_alloc(sizeof(struct tnl_vport), vport_ops, parms);
 	if (IS_ERR(vport)) {
 		err = PTR_ERR(vport);
 		goto error;
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index c74bce8..f6348be 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -105,16 +105,13 @@ static void internal_dev_getinfo(struct net_device *netdev,
 				 struct ethtool_drvinfo *info)
 {
 	struct vport *vport = internal_dev_get_vport(netdev);
-	struct dp_port *dp_port;
 
 	strcpy(info->driver, "openvswitch");
 
-	if (!vport)
+	if (!vport || !vport->dp)
 		return;
 
-	dp_port = vport_get_dp_port(vport);
-	if (dp_port)
-		sprintf(info->bus_info, "%d.%d", dp_port->dp->dp_idx, dp_port->port_no);
+	sprintf(info->bus_info, "%d.%d", vport->dp->dp_idx, vport->port_no);
 }
 
 static struct ethtool_ops internal_dev_ethtool_ops = {
@@ -135,14 +132,8 @@ static int internal_dev_change_mtu(struct net_device *netdev, int new_mtu)
 	if (new_mtu < 68)
 		return -EINVAL;
 
-	if (vport) {
-		struct dp_port *dp_port = vport_get_dp_port(vport);
-
-		if (dp_port) {
-			if (new_mtu > dp_min_mtu(dp_port->dp))
-				return -EINVAL;
-		}
-	}
+	if (vport && vport->dp && new_mtu > dp_min_mtu(vport->dp))
+		return -EINVAL;
 
 	netdev->mtu = new_mtu;
 	return 0;
@@ -202,7 +193,7 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
 	struct internal_dev *internal_dev;
 	int err;
 
-	vport = vport_alloc(sizeof(struct netdev_vport), &internal_vport_ops);
+	vport = vport_alloc(sizeof(struct netdev_vport), &internal_vport_ops, parms);
 	if (IS_ERR(vport)) {
 		err = PTR_ERR(vport);
 		goto error;
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index f32ab9f..d4536a4 100644
--- a/datapath/vport-netdev.c
+++ b/datapath/vport-netdev.c
@@ -94,7 +94,7 @@ static struct vport *netdev_create(const struct vport_parms *parms)
 	struct netdev_vport *netdev_vport;
 	int err;
 
-	vport = vport_alloc(sizeof(struct netdev_vport), &netdev_vport_ops);
+	vport = vport_alloc(sizeof(struct netdev_vport), &netdev_vport_ops, parms);
 	if (IS_ERR(vport)) {
 		err = PTR_ERR(vport);
 		goto error;
diff --git a/datapath/vport-patch.c b/datapath/vport-patch.c
index c69f006..52d3da1 100644
--- a/datapath/vport-patch.c
+++ b/datapath/vport-patch.c
@@ -95,12 +95,6 @@ static int set_config(struct vport *vport, const void *config)
 
 	strcpy(patch_vport->peer_name, peer_name);
 
-	if (vport_get_dp_port(vport)) {
-		hlist_del(&patch_vport->hash_node);
-		rcu_assign_pointer(patch_vport->peer, vport_locate(patch_vport->peer_name));
-		hlist_add_head(&patch_vport->hash_node, hash_bucket(patch_vport->peer_name));
-	}
-
 	return 0;
 }
 
@@ -110,7 +104,7 @@ static struct vport *patch_create(const struct vport_parms *parms)
 	struct patch_vport *patch_vport;
 	int err;
 
-	vport = vport_alloc(sizeof(struct patch_vport), &patch_vport_ops);
+	vport = vport_alloc(sizeof(struct patch_vport), &patch_vport_ops, parms);
 	if (IS_ERR(vport)) {
 		err = PTR_ERR(vport);
 		goto error;
@@ -146,7 +140,15 @@ error:
 
 static int patch_modify(struct vport *vport, struct odp_port *port)
 {
-	return set_config(vport, port->config);
+	int err = set_config(vport, port->config);
+	if (!err) {
+		struct patch_vport *patch_vport = patch_vport_priv(vport);
+
+		hlist_del(&patch_vport->hash_node);
+		rcu_assign_pointer(patch_vport->peer, vport_locate(patch_vport->peer_name));
+		hlist_add_head(&patch_vport->hash_node, hash_bucket(patch_vport->peer_name));
+	}
+	return err;
 }
 
 static int patch_destroy(struct vport *vport)
diff --git a/datapath/vport.c b/datapath/vport.c
index 6b50bd6..b67a34b 100644
--- a/datapath/vport.c
+++ b/datapath/vport.c
@@ -47,13 +47,12 @@ static struct hlist_head *dev_table;
  * one of these locks if you don't want the vport to be deleted out from under
  * you.
  *
- * If you get a reference to a vport through a dp_port, it is protected
+ * If you get a reference to a vport through a datapath, it is protected
  * by RCU and you need to hold rcu_read_lock instead when reading.
  *
  * If multiple locks are taken, the hierarchy is:
  * 1. RTNL
- * 2. DP
- * 3. vport
+ * 2. vport
  */
 static DEFINE_MUTEX(vport_mutex);
 
@@ -504,6 +503,19 @@ static void unregister_vport(struct vport *vport)
 	hlist_del(&vport->hash_node);
 }
 
+static void release_vport(struct kobject *kobj)
+{
+	struct vport *p = container_of(kobj, struct vport, kobj);
+	kfree(p);
+}
+
+static struct kobj_type brport_ktype = {
+#ifdef CONFIG_SYSFS
+	.sysfs_ops = &brport_sysfs_ops,
+#endif
+	.release = release_vport
+};
+
 /**
  *	vport_alloc - allocate and initialize new vport
  *
@@ -515,7 +527,7 @@ static void unregister_vport(struct vport *vport)
  * vport_priv().  vports that are no longer needed should be released with
  * vport_free().
  */
-struct vport *vport_alloc(int priv_size, const struct vport_ops *ops)
+struct vport *vport_alloc(int priv_size, const struct vport_ops *ops, const struct vport_parms *parms)
 {
 	struct vport *vport;
 	size_t alloc_size;
@@ -530,8 +542,16 @@ struct vport *vport_alloc(int priv_size, const struct vport_ops *ops)
 	if (!vport)
 		return ERR_PTR(-ENOMEM);
 
+	rcu_assign_pointer(vport->dp, parms->dp);
+	vport->port_no = parms->port_no;
+	atomic_set(&vport->sflow_pool, 0);
 	vport->ops = ops;
 
+	/* Initialize kobject for bridge.  This will be added as
+	 * /sys/class/net/<devname>/brport later, if sysfs is enabled. */
+	vport->kobj.kset = NULL;
+	kobject_init(&vport->kobj, &brport_ktype);
+
 	if (vport->ops->flags & VPORT_F_GEN_STATS) {
 		vport->percpu_stats = alloc_percpu(struct vport_percpu_stats);
 		if (!vport->percpu_stats)
@@ -555,7 +575,7 @@ void vport_free(struct vport *vport)
 	if (vport->ops->flags & VPORT_F_GEN_STATS)
 		free_percpu(vport->percpu_stats);
 
-	kfree(vport);
+	kobject_put(&vport->kobj);
 }
 
 /**
@@ -627,7 +647,6 @@ int vport_del(struct vport *vport)
 {
 	ASSERT_RTNL();
 	ASSERT_VPORT();
-	BUG_ON(vport_get_dp_port(vport));
 
 	unregister_vport(vport);
 
@@ -635,32 +654,19 @@ int vport_del(struct vport *vport)
 }
 
 /**
- *	vport_attach - attach a vport to a datapath
+ *	vport_attach - notify a vport that it has been attached to a datapath
  *
  * @vport: vport to attach.
- * @dp_port: Datapath port to attach the vport to.
  *
- * Attaches a vport to a specific datapath so that packets may be exchanged.
- * Both ports must be currently unattached.  @dp_port must be successfully
- * attached to a vport before it is connected to a datapath and must not be
- * modified while connected.  RTNL lock and the appropriate DP mutex must be held.
+ * Performs vport-specific actions so that packets may be exchanged.  RTNL lock
+ * and the appropriate DP mutex must be held.
  */
-int vport_attach(struct vport *vport, struct dp_port *dp_port)
+int vport_attach(struct vport *vport)
 {
 	ASSERT_RTNL();
 
-	if (vport_get_dp_port(vport))
-		return -EBUSY;
-
-	if (vport->ops->attach) {
-		int err;
-
-		err = vport->ops->attach(vport);
-		if (err)
-			return err;
-	}
-
-	rcu_assign_pointer(vport->dp_port, dp_port);
+	if (vport->ops->attach)
+		return vport->ops->attach(vport);
 
 	return 0;
 }
@@ -670,25 +676,17 @@ int vport_attach(struct vport *vport, struct dp_port *dp_port)
  *
  * @vport: vport to detach.
  *
- * Detaches a vport from a datapath.  May fail for a variety of reasons,
- * including lack of memory.  RTNL lock and the appropriate DP mutex must be held.
+ * Performs vport-specific actions before a vport is detached from a datapath.
+ * May fail for a variety of reasons, including lack of memory.  RTNL lock and
+ * the appropriate DP mutex must be held.
  */
 int vport_detach(struct vport *vport)
 {
-	struct dp_port *dp_port;
-
 	ASSERT_RTNL();
 
-	dp_port = vport_get_dp_port(vport);
-	if (!dp_port)
-		return -EINVAL;
-
-	rcu_assign_pointer(vport->dp_port, NULL);
-
 	if (vport->ops->detach)
 		return vport->ops->detach(vport);
-	else
-		return 0;
+	return 0;
 }
 
 /**
@@ -713,12 +711,8 @@ int vport_set_mtu(struct vport *vport, int mtu)
 
 		ret = vport->ops->set_mtu(vport, mtu);
 
-		if (!ret && !is_internal_vport(vport)) {
-			struct dp_port *dp_port = vport_get_dp_port(vport);
-
-			if (dp_port)
-				set_internal_devs_mtu(dp_port->dp);
-		}
+		if (!ret && !is_internal_vport(vport))
+			set_internal_devs_mtu(vport->dp);
 
 		return ret;
 	} else
@@ -816,20 +810,6 @@ const unsigned char *vport_get_addr(const struct vport *vport)
 }
 
 /**
- *	vport_get_dp_port - retrieve attached datapath port
- *
- * @vport: vport from which to retrieve the datapath port.
- *
- * Retrieves the attached datapath port or null if not attached.  Either RTNL
- * lock or rcu_read_lock must be held for the entire duration that the datapath
- * port is being accessed.
- */
-struct dp_port *vport_get_dp_port(const struct vport *vport)
-{
-	return rcu_dereference(vport->dp_port);
-}
-
-/**
  *	vport_get_kobj - retrieve associated kobj
  *
  * @vport: vport from which to retrieve the associated kobj
@@ -1004,18 +984,12 @@ unsigned char vport_get_operstate(const struct vport *vport)
  */
 int vport_get_ifindex(const struct vport *vport)
 {
-	const struct dp_port *dp_port;
-
 	if (vport->ops->get_ifindex)
 		return vport->ops->get_ifindex(vport);
 
 	/* If we don't actually have an ifindex, use the local port's.
 	 * Userspace doesn't check it anyways. */
-	dp_port = vport_get_dp_port(vport);
-	if (!dp_port)
-		return -EAGAIN;
-
-	return vport_get_ifindex(dp_port->dp->ports[ODPP_LOCAL]->vport);
+	return vport_get_ifindex(vport->dp->ports[ODPP_LOCAL]);
 }
 
 /**
@@ -1064,15 +1038,6 @@ int vport_get_mtu(const struct vport *vport)
  */
 void vport_receive(struct vport *vport, struct sk_buff *skb)
 {
-	struct dp_port *dp_port = vport_get_dp_port(vport);
-
-	if (!dp_port) {
-		vport_record_error(vport, VPORT_E_RX_DROPPED);
-		kfree_skb(skb);
-
-		return;
-	}
-
 	if (vport->ops->flags & VPORT_F_GEN_STATS) {
 		struct vport_percpu_stats *stats;
 
@@ -1093,7 +1058,7 @@ void vport_receive(struct vport *vport, struct sk_buff *skb)
 	if (!(vport->ops->flags & VPORT_F_TUN_ID))
 		OVS_CB(skb)->tun_id = 0;
 
-	dp_process_received_packet(dp_port, skb);
+	dp_process_received_packet(vport, skb);
 }
 
 static inline unsigned packet_length(const struct sk_buff *skb)
@@ -1124,8 +1089,7 @@ int vport_send(struct vport *vport, struct sk_buff *skb)
 	if (unlikely(packet_length(skb) > mtu && !skb_is_gso(skb))) {
 		if (net_ratelimit())
 			pr_warn("%s: dropped over-mtu packet: %d > %d\n",
-				dp_name(vport_get_dp_port(vport)->dp),
-				packet_length(skb), mtu);
+				dp_name(vport->dp), packet_length(skb), mtu);
 		goto error;
 	}
 
diff --git a/datapath/vport.h b/datapath/vport.h
index 1fcc962..13772c7 100644
--- a/datapath/vport.h
+++ b/datapath/vport.h
@@ -20,7 +20,6 @@
 
 struct vport;
 struct vport_parms;
-struct dp_port;
 
 /* The following definitions are for users of the vport subsytem: */
 
@@ -46,7 +45,7 @@ int vport_del(struct vport *);
 
 struct vport *vport_locate(const char *name);
 
-int vport_attach(struct vport *, struct dp_port *);
+int vport_attach(struct vport *);
 int vport_detach(struct vport *);
 
 int vport_set_mtu(struct vport *, int mtu);
@@ -57,7 +56,6 @@ const char *vport_get_name(const struct vport *);
 const char *vport_get_type(const struct vport *);
 const unsigned char *vport_get_addr(const struct vport *);
 
-struct dp_port *vport_get_dp_port(const struct vport *);
 struct kobject *vport_get_kobj(const struct vport *);
 int vport_get_stats(struct vport *, struct rtnl_link_stats64 *);
 
@@ -93,10 +91,37 @@ struct vport_err_stats {
 	u64 collisions;
 };
 
+/**
+ * struct vport - one port within a datapath
+ * @port_no: Index into @dp's @ports array.
+ * @dp: Datapath to which this port belongs.
+ * @kobj: Represents /sys/class/net/<devname>/brport.
+ * @linkname: The name of the link from /sys/class/net/<datapath>/brif to this
+ * &struct vport.  (We keep this around so that we can delete it if the
+ * device 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.
+ * @hash_node: Element in @dev_table hash table in vport.c.
+ * @ops: Class structure.
+ * @percpu_stats: Points to per-CPU statistics used and maintained by the vport
+ * code if %VPORT_F_GEN_STATS is set to 1 in @ops flags, otherwise unused.
+ * @stats_lock: Protects @err_stats and @offset_stats.
+ * @err_stats: Points to error statistics used and maintained by the vport code
+ * if %VPORT_F_GEN_STATS is set to 1 in @ops flags, otherwise unused.
+ * @offset_stats: Added to actual statistics as a sop to compatibility with
+ * XAPI for Citrix XenServer.  Deprecated.
+ */
 struct vport {
+	u16 port_no;
+	struct datapath	*dp;
+	struct kobject kobj;
+	char linkname[IFNAMSIZ];
+	struct list_head node;
+	atomic_t sflow_pool;
+
 	struct hlist_node hash_node;
 	const struct vport_ops *ops;
-	struct dp_port *dp_port;
 
 	struct vport_percpu_stats *percpu_stats;
 
@@ -117,11 +142,17 @@ struct vport {
  * @type: New vport's type.
  * @config: Kernel copy of 'config' member of &struct odp_port describing
  * configuration for new port.  Exactly %VPORT_CONFIG_SIZE bytes.
+ * @dp: New vport's datapath.
+ * @port_no: New vport's port number.
  */
 struct vport_parms {
 	const char *name;
 	const char *type;
 	const void *config;
+
+	/* For vport_alloc(). */
+	struct datapath *dp;
+	u16 port_no;
 };
 
 /**
@@ -216,7 +247,7 @@ enum vport_err_type {
 	VPORT_E_COLLISION,
 };
 
-struct vport *vport_alloc(int priv_size, const struct vport_ops *);
+struct vport *vport_alloc(int priv_size, const struct vport_ops *, const struct vport_parms *);
 void vport_free(struct vport *);
 
 #define VPORT_ALIGN 8
-- 
1.7.1





More information about the dev mailing list