From: Ben Pfaff Date: Fri, 3 Dec 2010 21:09:26 +0000 (-0800) Subject: datapath: Merge "struct dp_port" into "struct vport". X-Git-Tag: v1.1.0~754 X-Git-Url: http://git.onelab.eu/?a=commitdiff_plain;h=e779d8d90d65297473febcf82ec44c9225cc4fe3;p=sliver-openvswitch.git datapath: Merge "struct dp_port" into "struct vport". 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 Acked-by: Jesse Gross --- diff --git a/datapath/actions.c b/datapath/actions.c index 5904c8312..41812a454 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 dc91fecac..382a8c279 100644 --- a/datapath/datapath.c +++ b/datapath/datapath.c @@ -63,13 +63,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) @@ -95,7 +95,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) @@ -110,12 +110,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; @@ -134,21 +134,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); @@ -160,7 +159,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; @@ -253,7 +252,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; @@ -291,7 +290,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) @@ -334,30 +333,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); @@ -366,31 +353,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//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; } @@ -421,7 +394,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; @@ -438,9 +411,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(); @@ -454,7 +426,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; @@ -462,17 +434,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; @@ -502,7 +472,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; @@ -511,7 +481,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; @@ -757,8 +727,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; @@ -1382,7 +1352,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(); @@ -1392,10 +1362,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; } @@ -1407,7 +1377,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(); @@ -1415,20 +1385,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; @@ -1445,7 +1415,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'; @@ -1458,14 +1427,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(); @@ -1488,7 +1455,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 36accfdf6..07406da12 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//brport. - * @linkname: The name of the link from /sys/class/net//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 1843d7569..e7d08bc35 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 2d688ac7f..49af58a22 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 4abe4fb63..413dfc31c 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//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 b40523aae..fc7c2d8e9 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//brport/bridge to * /sys/class/net/. */ - 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//brif/ to * /sys/class/net//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 b6bd6f65d..37ec4d9ef 100644 --- a/datapath/tunnel.c +++ b/datapath/tunnel.c @@ -883,22 +883,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; @@ -906,13 +901,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) { @@ -1352,7 +1347,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 c4de2be66..c0e250db5 100644 --- a/datapath/vport-internal_dev.c +++ b/datapath/vport-internal_dev.c @@ -97,16 +97,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) 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 const struct ethtool_ops internal_dev_ethtool_ops = { @@ -127,14 +124,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 && new_mtu > dp_min_mtu(vport->dp)) + return -EINVAL; netdev->mtu = new_mtu; return 0; @@ -194,7 +185,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 33fe9a513..c97e0a0cd 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 b5276b171..4b5137de2 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 272324430..ee8064536 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -47,7 +47,7 @@ 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: @@ -497,6 +497,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 * @@ -508,7 +521,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; @@ -523,8 +536,16 @@ struct vport *vport_alloc(int priv_size, const struct vport_ops *ops) if (!vport) return ERR_PTR(-ENOMEM); + 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//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) @@ -548,7 +569,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); } /** @@ -620,7 +641,6 @@ int vport_del(struct vport *vport) { ASSERT_RTNL(); ASSERT_VPORT(); - BUG_ON(vport_get_dp_port(vport)); unregister_vport(vport); @@ -628,32 +648,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; } @@ -663,25 +670,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; } /** @@ -706,12 +705,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 @@ -808,20 +803,6 @@ const unsigned char *vport_get_addr(const struct vport *vport) return vport->ops->get_addr(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 * @@ -990,18 +971,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]); } /** @@ -1050,15 +1025,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; @@ -1079,7 +1045,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) @@ -1110,8 +1076,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 7251b4cdf..f49ecc83f 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: */ @@ -45,7 +44,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); @@ -56,7 +55,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 *); @@ -88,10 +86,37 @@ struct vport_err_stats { u64 tx_errors; }; +/** + * 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//brport. + * @linkname: The name of the link from /sys/class/net//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; @@ -112,11 +137,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; }; /** @@ -207,7 +238,7 @@ enum vport_err_type { VPORT_E_TX_ERROR, }; -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