X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;ds=sidebyside;f=datapath%2Fvport-patch.c;h=4fdbcf5278d6558f7f75519b0f96687d9e1554cf;hb=d2bb2799e1b7cf2177140cf4ca8a60312c87625a;hp=ff94be00a5840ca569cb00a588e5daaf90677a75;hpb=5953c70e61897996e8b05fadea988b3289e133de;p=openvswitch diff --git a/datapath/vport-patch.c b/datapath/vport-patch.c index ff94be00..4fdbcf52 100644 --- a/datapath/vport-patch.c +++ b/datapath/vport-patch.c @@ -9,6 +9,7 @@ #include #include #include +#include #include "datapath.h" #include "vport.h" @@ -22,57 +23,54 @@ struct device_config { }; struct patch_vport { + struct rcu_head rcu; + char name[IFNAMSIZ]; /* Protected by RTNL lock. */ char peer_name[IFNAMSIZ]; struct hlist_node hash_node; - /* Protected by RCU. */ - struct vport *peer; - - /* Protected by RCU. */ - struct device_config *devconf; + struct vport __rcu *peer; + struct device_config __rcu *devconf; }; /* Protected by RTNL lock. */ static struct hlist_head *peer_table; #define PEER_HASH_BUCKETS 256 -static inline struct patch_vport * -patch_vport_priv(const struct vport *vport) +static void update_peers(const char *name, struct vport *); + +static inline struct patch_vport *patch_vport_priv(const struct vport *vport) { return vport_priv(vport); } /* RCU callback. */ -static void -free_config(struct rcu_head *rcu) +static void free_config(struct rcu_head *rcu) { struct device_config *c = container_of(rcu, struct device_config, rcu); kfree(c); } -static void -assign_config_rcu(struct vport *vport, struct device_config *new_config) +static void assign_config_rcu(struct vport *vport, + struct device_config *new_config) { struct patch_vport *patch_vport = patch_vport_priv(vport); struct device_config *old_config; - old_config = rcu_dereference(patch_vport->devconf); + old_config = rtnl_dereference(patch_vport->devconf); rcu_assign_pointer(patch_vport->devconf, new_config); call_rcu(&old_config->rcu, free_config); } -static struct hlist_head * -hash_bucket(const char *name) +static struct hlist_head *hash_bucket(const char *name) { unsigned int hash = full_name_hash(name, strlen(name)); return &peer_table[hash & (PEER_HASH_BUCKETS - 1)]; } -static int -patch_init(void) +static int patch_init(void) { peer_table = kzalloc(PEER_HASH_BUCKETS * sizeof(struct hlist_head), GFP_KERNEL); @@ -82,47 +80,33 @@ patch_init(void) return 0; } -static void -patch_exit(void) +static void patch_exit(void) { kfree(peer_table); } -static int -set_config(struct vport *vport, const void __user *uconfig) +static int set_config(struct vport *vport, const void *config) { struct patch_vport *patch_vport = patch_vport_priv(vport); char peer_name[IFNAMSIZ]; - int retval; - retval = strncpy_from_user(peer_name, uconfig, IFNAMSIZ); - if (retval < 0) - return -EFAULT; - else if (retval >= IFNAMSIZ) - return -ENAMETOOLONG; + strlcpy(peer_name, config, IFNAMSIZ); if (!strcmp(patch_vport->name, peer_name)) return -EINVAL; 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; } -static struct vport * -patch_create(const char *name, const void __user *config) +static struct vport *patch_create(const struct vport_parms *parms) { struct vport *vport; 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; @@ -130,9 +114,9 @@ patch_create(const char *name, const void __user *config) patch_vport = patch_vport_priv(vport); - strcpy(patch_vport->name, name); + strcpy(patch_vport->name, parms->name); - err = set_config(vport, config); + err = set_config(vport, parms->config); if (err) goto error_free_vport; @@ -143,7 +127,15 @@ patch_create(const char *name, const void __user *config) } vport_gen_rand_ether_addr(patch_vport->devconf->eth_addr); - patch_vport->devconf->mtu = ETH_DATA_LEN; + + /* Make the default MTU fairly large so that it doesn't become the + * bottleneck on systems using jumbo frames. */ + patch_vport->devconf->mtu = 65535; + + hlist_add_head(&patch_vport->hash_node, hash_bucket(patch_vport->peer_name)); + + rcu_assign_pointer(patch_vport->peer, vport_locate(patch_vport->peer_name)); + update_peers(patch_vport->name, vport); return vport; @@ -153,25 +145,40 @@ error: return ERR_PTR(err); } -static int -patch_modify(struct vport *vport, const void __user *config) +static int patch_modify(struct vport *vport, struct odp_port *port) { - return set_config(vport, 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) +static void free_port_rcu(struct rcu_head *rcu) { - struct patch_vport *patch_vport = patch_vport_priv(vport); + struct patch_vport *patch_vport = container_of(rcu, + struct patch_vport, rcu); kfree(patch_vport->devconf); - vport_free(vport); + vport_free(vport_from_priv(patch_vport)); +} + +static int patch_destroy(struct vport *vport) +{ + struct patch_vport *patch_vport = patch_vport_priv(vport); + + update_peers(patch_vport->name, NULL); + hlist_del(&patch_vport->hash_node); + call_rcu(&patch_vport->rcu, free_port_rcu); return 0; } -static void -update_peers(const char *name, struct vport *vport) +static void update_peers(const char *name, struct vport *vport) { struct hlist_head *bucket = hash_bucket(name); struct patch_vport *peer_vport; @@ -182,34 +189,7 @@ update_peers(const char *name, struct vport *vport) rcu_assign_pointer(peer_vport->peer, vport); } -static int -patch_attach(struct vport *vport) -{ - struct patch_vport *patch_vport = patch_vport_priv(vport); - - hlist_add_head(&patch_vport->hash_node, hash_bucket(patch_vport->peer_name)); - - rcu_assign_pointer(patch_vport->peer, vport_locate(patch_vport->peer_name)); - update_peers(patch_vport->name, vport); - - return 0; -} - -static int -patch_detach(struct vport *vport) -{ - struct patch_vport *patch_vport = patch_vport_priv(vport); - - update_peers(patch_vport->name, NULL); - rcu_assign_pointer(patch_vport->peer, NULL); - - hlist_del(&patch_vport->hash_node); - - return 0; -} - -static int -patch_set_mtu(struct vport *vport, int mtu) +static int patch_set_mtu(struct vport *vport, int mtu) { struct patch_vport *patch_vport = patch_vport_priv(vport); struct device_config *devconf; @@ -224,8 +204,7 @@ patch_set_mtu(struct vport *vport, int mtu) return 0; } -static int -patch_set_addr(struct vport *vport, const unsigned char *addr) +static int patch_set_addr(struct vport *vport, const unsigned char *addr) { struct patch_vport *patch_vport = patch_vport_priv(vport); struct device_config *devconf; @@ -241,29 +220,25 @@ patch_set_addr(struct vport *vport, const unsigned char *addr) } -static const char * -patch_get_name(const struct vport *vport) +static const char *patch_get_name(const struct vport *vport) { const struct patch_vport *patch_vport = patch_vport_priv(vport); return patch_vport->name; } -static const unsigned char * -patch_get_addr(const struct vport *vport) +static const unsigned char *patch_get_addr(const struct vport *vport) { const struct patch_vport *patch_vport = patch_vport_priv(vport); - return rcu_dereference(patch_vport->devconf)->eth_addr; + return rcu_dereference_rtnl(patch_vport->devconf)->eth_addr; } -static int -patch_get_mtu(const struct vport *vport) +static int patch_get_mtu(const struct vport *vport) { const struct patch_vport *patch_vport = patch_vport_priv(vport); - return rcu_dereference(patch_vport->devconf)->mtu; + return rcu_dereference_rtnl(patch_vport->devconf)->mtu; } -static int -patch_send(struct vport *vport, struct sk_buff *skb) +static int patch_send(struct vport *vport, struct sk_buff *skb) { struct patch_vport *patch_vport = patch_vport_priv(vport); struct vport *peer = rcu_dereference(patch_vport->peer); @@ -280,7 +255,7 @@ patch_send(struct vport *vport, struct sk_buff *skb) return skb_len; } -struct vport_ops patch_vport_ops = { +const struct vport_ops patch_vport_ops = { .type = "patch", .flags = VPORT_F_GEN_STATS, .init = patch_init, @@ -288,8 +263,6 @@ struct vport_ops patch_vport_ops = { .create = patch_create, .modify = patch_modify, .destroy = patch_destroy, - .attach = patch_attach, - .detach = patch_detach, .set_mtu = patch_set_mtu, .set_addr = patch_set_addr, .get_name = patch_get_name,