X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=datapath%2Fvport.c;h=945ef448589c6aef7802dadc93cb43731ee5f11f;hb=823c5699d4de7bf726f988e1ca6197fb2400f388;hp=a166ef900e0482e0a9bfaa27167e447b928e4214;hpb=f2459fe7d91c4c325dfaa3ed18f56200b63ae27e;p=openvswitch diff --git a/datapath/vport.c b/datapath/vport.c index a166ef90..945ef448 100644 --- a/datapath/vport.c +++ b/datapath/vport.c @@ -14,16 +14,21 @@ #include #include #include +#include #include "vport.h" +#include "vport-internal_dev.h" extern struct vport_ops netdev_vport_ops; extern struct vport_ops internal_vport_ops; +extern struct vport_ops patch_vport_ops; extern struct vport_ops gre_vport_ops; static struct vport_ops *base_vport_ops_list[] = { &netdev_vport_ops, &internal_vport_ops, + &patch_vport_ops, + &gre_vport_ops, }; static const struct vport_ops **vport_ops_list; @@ -186,30 +191,26 @@ vport_exit(void) * on device type). This function is for userspace callers and assumes no * locks are held. */ -int -vport_add(const struct odp_vport_add __user *uvport_config) +static int +do_vport_add(struct odp_vport_add *vport_config) { - struct odp_vport_add vport_config; struct vport *vport; int err = 0; - if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_add))) - return -EFAULT; - - vport_config.port_type[VPORT_TYPE_SIZE - 1] = '\0'; - vport_config.devname[IFNAMSIZ - 1] = '\0'; + vport_config->port_type[VPORT_TYPE_SIZE - 1] = '\0'; + vport_config->devname[IFNAMSIZ - 1] = '\0'; rtnl_lock(); - vport = vport_locate(vport_config.devname); + vport = vport_locate(vport_config->devname); if (vport) { err = -EEXIST; goto out; } vport_lock(); - vport = __vport_add(vport_config.devname, vport_config.port_type, - vport_config.config); + vport = __vport_add(vport_config->devname, vport_config->port_type, + vport_config->config); vport_unlock(); if (IS_ERR(vport)) @@ -220,6 +221,35 @@ out: return err; } +int +vport_add(const struct odp_vport_add __user *uvport_config) +{ + struct odp_vport_add vport_config; + + if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_add))) + return -EFAULT; + + return do_vport_add(&vport_config); +} + +#ifdef CONFIG_COMPAT +int +compat_vport_add(struct compat_odp_vport_add *ucompat) +{ + struct compat_odp_vport_add compat; + struct odp_vport_add vport_config; + + if (copy_from_user(&compat, ucompat, sizeof(struct compat_odp_vport_add))) + return -EFAULT; + + memcpy(vport_config.port_type, compat.port_type, VPORT_TYPE_SIZE); + memcpy(vport_config.devname, compat.devname, IFNAMSIZ); + vport_config.config = compat_ptr(compat.config); + + return do_vport_add(&vport_config); +} +#endif + /** * vport_mod - modify existing vport device (for userspace callers) * @@ -229,28 +259,24 @@ out: * dependent on device type). This function is for userspace callers and * assumes no locks are held. */ -int -vport_mod(const struct odp_vport_mod __user *uvport_config) +static int +do_vport_mod(struct odp_vport_mod *vport_config) { - struct odp_vport_mod vport_config; struct vport *vport; int err; - if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_mod))) - return -EFAULT; - - vport_config.devname[IFNAMSIZ - 1] = '\0'; + vport_config->devname[IFNAMSIZ - 1] = '\0'; rtnl_lock(); - vport = vport_locate(vport_config.devname); + vport = vport_locate(vport_config->devname); if (!vport) { err = -ENODEV; goto out; } vport_lock(); - err = __vport_mod(vport, vport_config.config); + err = __vport_mod(vport, vport_config->config); vport_unlock(); out: @@ -258,6 +284,34 @@ out: return err; } +int +vport_mod(const struct odp_vport_mod __user *uvport_config) +{ + struct odp_vport_mod vport_config; + + if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_mod))) + return -EFAULT; + + return do_vport_mod(&vport_config); +} + +#ifdef CONFIG_COMPAT +int +compat_vport_mod(struct compat_odp_vport_mod *ucompat) +{ + struct compat_odp_vport_mod compat; + struct odp_vport_mod vport_config; + + if (copy_from_user(&compat, ucompat, sizeof(struct compat_odp_vport_mod))) + return -EFAULT; + + memcpy(vport_config.devname, compat.devname, IFNAMSIZ); + vport_config.config = compat_ptr(compat.config); + + return do_vport_mod(&vport_config); +} +#endif + /** * vport_del - delete existing vport device (for userspace callers) * @@ -276,10 +330,13 @@ vport_del(const char __user *udevname) struct vport *vport; struct dp_port *dp_port; int err = 0; + int retval; - if (strncpy_from_user(devname, udevname, IFNAMSIZ - 1) < 0) + retval = strncpy_from_user(devname, udevname, IFNAMSIZ); + if (retval < 0) return -EFAULT; - devname[IFNAMSIZ - 1] = '\0'; + else if (retval >= IFNAMSIZ) + return -ENAMETOOLONG; rtnl_lock(); @@ -346,9 +403,12 @@ vport_stats_get(struct odp_vport_stats_req __user *ustats_req) goto out; } - if (vport->ops->get_stats) + if (vport->ops->get_stats) { + rcu_read_lock(); err = vport->ops->get_stats(vport, &stats_req.stats); - else if (vport->ops->flags & VPORT_F_GEN_STATS) { + rcu_read_unlock(); + + } else if (vport->ops->flags & VPORT_F_GEN_STATS) { int i; memset(&stats_req.stats, 0, sizeof(struct odp_vport_stats)); @@ -421,7 +481,9 @@ vport_ether_get(struct odp_vport_ether __user *uvport_ether) goto out; } + rcu_read_lock(); memcpy(vport_ether.ether_addr, vport_get_addr(vport), ETH_ALEN); + rcu_read_unlock(); out: vport_unlock(); @@ -578,11 +640,17 @@ vport_locate(const char *name) dump_stack(); } + rcu_read_lock(); + hlist_for_each_entry(vport, node, bucket, hash_node) if (!strcmp(name, vport_get_name(vport))) - return vport; + goto out; - return NULL; + vport = NULL; + +out: + rcu_read_unlock(); + return vport; } static void @@ -817,9 +885,20 @@ vport_set_mtu(struct vport *vport, int mtu) if (mtu < 68) return -EINVAL; - if (vport->ops->set_mtu) - return vport->ops->set_mtu(vport, mtu); - else + if (vport->ops->set_mtu) { + int ret; + + 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); + } + + return ret; + } else return -EOPNOTSUPP; } @@ -1033,16 +1112,21 @@ vport_get_mtu(const struct vport *vport) * @vport: vport that received the packet * @skb: skb that was received * - * Must be called with rcu_read_lock and bottom halves disabled. The packet - * cannot be shared and skb->data should point to the Ethernet header. + * Must be called with rcu_read_lock. The packet cannot be shared and + * skb->data should point to the Ethernet header. The caller must have already + * called compute_ip_summed() to initialize the checksumming fields. */ void vport_receive(struct vport *vport, struct sk_buff *skb) { struct dp_port *dp_port = vport_get_dp_port(vport); - if (!dp_port) + 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; @@ -1146,25 +1230,3 @@ vport_record_error(struct vport *vport, enum vport_err_type err_type) spin_unlock_bh(&vport->err_stats.lock); } } - -/** - * vport_gen_ether_addr - generate an Ethernet address - * - * @addr: location to store generated address - * - * Generates a random Ethernet address for use when creating a device that - * has no natural address. - */ -void -vport_gen_ether_addr(u8 *addr) -{ - random_ether_addr(addr); - - /* Set the OUI to the Nicira one. */ - addr[0] = 0x00; - addr[1] = 0x23; - addr[2] = 0x20; - - /* Set the top bit to indicate random address. */ - addr[3] |= 0x80; -}