Commit 46df7b81 authored by Pravin B Shelar's avatar Pravin B Shelar Committed by Jesse Gross

openvswitch: Add support for network namespaces.

Following patch adds support for network namespace to openvswitch.
Since it must release devices when namespaces are destroyed, a
side effect of this patch is that the module no longer keeps a
refcount but instead cleans up any state when it is unloaded.
Signed-off-by: default avatarPravin B Shelar <pshelar@nicira.com>
Signed-off-by: default avatarJesse Gross <jesse@nicira.com>
parent 0d7614f0
This diff is collapsed.
...@@ -27,8 +27,7 @@ ...@@ -27,8 +27,7 @@
#include <linux/u64_stats_sync.h> #include <linux/u64_stats_sync.h>
#include "flow.h" #include "flow.h"
#include "vport.h"
struct vport;
#define DP_MAX_PORTS 1024 #define DP_MAX_PORTS 1024
#define SAMPLE_ACTION_DEPTH 3 #define SAMPLE_ACTION_DEPTH 3
...@@ -63,6 +62,7 @@ struct dp_stats_percpu { ...@@ -63,6 +62,7 @@ struct dp_stats_percpu {
* @port_list: List of all ports in @ports in arbitrary order. RTNL required * @port_list: List of all ports in @ports in arbitrary order. RTNL required
* to iterate or modify. * to iterate or modify.
* @stats_percpu: Per-CPU datapath statistics. * @stats_percpu: Per-CPU datapath statistics.
* @net: Reference to net namespace.
* *
* Context: See the comment on locking at the top of datapath.c for additional * Context: See the comment on locking at the top of datapath.c for additional
* locking information. * locking information.
...@@ -80,6 +80,11 @@ struct datapath { ...@@ -80,6 +80,11 @@ struct datapath {
/* Stats. */ /* Stats. */
struct dp_stats_percpu __percpu *stats_percpu; struct dp_stats_percpu __percpu *stats_percpu;
#ifdef CONFIG_NET_NS
/* Network namespace ref. */
struct net *net;
#endif
}; };
/** /**
...@@ -108,6 +113,16 @@ struct dp_upcall_info { ...@@ -108,6 +113,16 @@ struct dp_upcall_info {
u32 pid; u32 pid;
}; };
static inline struct net *ovs_dp_get_net(struct datapath *dp)
{
return read_pnet(&dp->net);
}
static inline void ovs_dp_set_net(struct datapath *dp, struct net *net)
{
write_pnet(&dp->net, net);
}
extern struct notifier_block ovs_dp_device_notifier; extern struct notifier_block ovs_dp_device_notifier;
extern struct genl_multicast_group ovs_dp_vport_multicast_group; extern struct genl_multicast_group ovs_dp_vport_multicast_group;
......
...@@ -41,19 +41,21 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event, ...@@ -41,19 +41,21 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
case NETDEV_UNREGISTER: case NETDEV_UNREGISTER:
if (!ovs_is_internal_dev(dev)) { if (!ovs_is_internal_dev(dev)) {
struct sk_buff *notify; struct sk_buff *notify;
struct datapath *dp = vport->dp;
notify = ovs_vport_cmd_build_info(vport, 0, 0, notify = ovs_vport_cmd_build_info(vport, 0, 0,
OVS_VPORT_CMD_DEL); OVS_VPORT_CMD_DEL);
ovs_dp_detach_port(vport); ovs_dp_detach_port(vport);
if (IS_ERR(notify)) { if (IS_ERR(notify)) {
netlink_set_err(init_net.genl_sock, 0, netlink_set_err(ovs_dp_get_net(dp)->genl_sock, 0,
ovs_dp_vport_multicast_group.id, ovs_dp_vport_multicast_group.id,
PTR_ERR(notify)); PTR_ERR(notify));
break; break;
} }
genlmsg_multicast(notify, 0, ovs_dp_vport_multicast_group.id, genlmsg_multicast_netns(ovs_dp_get_net(dp), notify, 0,
GFP_KERNEL); ovs_dp_vport_multicast_group.id,
GFP_KERNEL);
} }
break; break;
} }
......
...@@ -144,7 +144,7 @@ static void do_setup(struct net_device *netdev) ...@@ -144,7 +144,7 @@ static void do_setup(struct net_device *netdev)
netdev->tx_queue_len = 0; netdev->tx_queue_len = 0;
netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST | netdev->features = NETIF_F_LLTX | NETIF_F_SG | NETIF_F_FRAGLIST |
NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_TSO; NETIF_F_HIGHDMA | NETIF_F_HW_CSUM | NETIF_F_TSO;
netdev->vlan_features = netdev->features; netdev->vlan_features = netdev->features;
netdev->features |= NETIF_F_HW_VLAN_TX; netdev->features |= NETIF_F_HW_VLAN_TX;
...@@ -175,9 +175,14 @@ static struct vport *internal_dev_create(const struct vport_parms *parms) ...@@ -175,9 +175,14 @@ static struct vport *internal_dev_create(const struct vport_parms *parms)
goto error_free_vport; goto error_free_vport;
} }
dev_net_set(netdev_vport->dev, ovs_dp_get_net(vport->dp));
internal_dev = internal_dev_priv(netdev_vport->dev); internal_dev = internal_dev_priv(netdev_vport->dev);
internal_dev->vport = vport; internal_dev->vport = vport;
/* Restrict bridge port to current netns. */
if (vport->port_no == OVSP_LOCAL)
netdev_vport->dev->features |= NETIF_F_NETNS_LOCAL;
err = register_netdevice(netdev_vport->dev); err = register_netdevice(netdev_vport->dev);
if (err) if (err)
goto error_free_netdev; goto error_free_netdev;
......
...@@ -83,7 +83,7 @@ static struct vport *netdev_create(const struct vport_parms *parms) ...@@ -83,7 +83,7 @@ static struct vport *netdev_create(const struct vport_parms *parms)
netdev_vport = netdev_vport_priv(vport); netdev_vport = netdev_vport_priv(vport);
netdev_vport->dev = dev_get_by_name(&init_net, parms->name); netdev_vport->dev = dev_get_by_name(ovs_dp_get_net(vport->dp), parms->name);
if (!netdev_vport->dev) { if (!netdev_vport->dev) {
err = -ENODEV; err = -ENODEV;
goto error_free_vport; goto error_free_vport;
......
...@@ -16,10 +16,10 @@ ...@@ -16,10 +16,10 @@
* 02110-1301, USA * 02110-1301, USA
*/ */
#include <linux/dcache.h>
#include <linux/etherdevice.h> #include <linux/etherdevice.h>
#include <linux/if.h> #include <linux/if.h>
#include <linux/if_vlan.h> #include <linux/if_vlan.h>
#include <linux/jhash.h>
#include <linux/kernel.h> #include <linux/kernel.h>
#include <linux/list.h> #include <linux/list.h>
#include <linux/mutex.h> #include <linux/mutex.h>
...@@ -27,7 +27,9 @@ ...@@ -27,7 +27,9 @@
#include <linux/rcupdate.h> #include <linux/rcupdate.h>
#include <linux/rtnetlink.h> #include <linux/rtnetlink.h>
#include <linux/compat.h> #include <linux/compat.h>
#include <net/net_namespace.h>
#include "datapath.h"
#include "vport.h" #include "vport.h"
#include "vport-internal_dev.h" #include "vport-internal_dev.h"
...@@ -67,9 +69,9 @@ void ovs_vport_exit(void) ...@@ -67,9 +69,9 @@ void ovs_vport_exit(void)
kfree(dev_table); kfree(dev_table);
} }
static struct hlist_head *hash_bucket(const char *name) static struct hlist_head *hash_bucket(struct net *net, const char *name)
{ {
unsigned int hash = full_name_hash(name, strlen(name)); unsigned int hash = jhash(name, strlen(name), (unsigned long) net);
return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)]; return &dev_table[hash & (VPORT_HASH_BUCKETS - 1)];
} }
...@@ -80,14 +82,15 @@ static struct hlist_head *hash_bucket(const char *name) ...@@ -80,14 +82,15 @@ static struct hlist_head *hash_bucket(const char *name)
* *
* Must be called with RTNL or RCU read lock. * Must be called with RTNL or RCU read lock.
*/ */
struct vport *ovs_vport_locate(const char *name) struct vport *ovs_vport_locate(struct net *net, const char *name)
{ {
struct hlist_head *bucket = hash_bucket(name); struct hlist_head *bucket = hash_bucket(net, name);
struct vport *vport; struct vport *vport;
struct hlist_node *node; struct hlist_node *node;
hlist_for_each_entry_rcu(vport, node, bucket, hash_node) hlist_for_each_entry_rcu(vport, node, bucket, hash_node)
if (!strcmp(name, vport->ops->get_name(vport))) if (!strcmp(name, vport->ops->get_name(vport)) &&
net_eq(ovs_dp_get_net(vport->dp), net))
return vport; return vport;
return NULL; return NULL;
...@@ -170,14 +173,17 @@ struct vport *ovs_vport_add(const struct vport_parms *parms) ...@@ -170,14 +173,17 @@ struct vport *ovs_vport_add(const struct vport_parms *parms)
for (i = 0; i < ARRAY_SIZE(vport_ops_list); i++) { for (i = 0; i < ARRAY_SIZE(vport_ops_list); i++) {
if (vport_ops_list[i]->type == parms->type) { if (vport_ops_list[i]->type == parms->type) {
struct hlist_head *bucket;
vport = vport_ops_list[i]->create(parms); vport = vport_ops_list[i]->create(parms);
if (IS_ERR(vport)) { if (IS_ERR(vport)) {
err = PTR_ERR(vport); err = PTR_ERR(vport);
goto out; goto out;
} }
hlist_add_head_rcu(&vport->hash_node, bucket = hash_bucket(ovs_dp_get_net(vport->dp),
hash_bucket(vport->ops->get_name(vport))); vport->ops->get_name(vport));
hlist_add_head_rcu(&vport->hash_node, bucket);
return vport; return vport;
} }
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#define VPORT_H 1 #define VPORT_H 1
#include <linux/list.h> #include <linux/list.h>
#include <linux/netlink.h>
#include <linux/openvswitch.h> #include <linux/openvswitch.h>
#include <linux/skbuff.h> #include <linux/skbuff.h>
#include <linux/spinlock.h> #include <linux/spinlock.h>
...@@ -38,7 +39,7 @@ void ovs_vport_exit(void); ...@@ -38,7 +39,7 @@ void ovs_vport_exit(void);
struct vport *ovs_vport_add(const struct vport_parms *); struct vport *ovs_vport_add(const struct vport_parms *);
void ovs_vport_del(struct vport *); void ovs_vport_del(struct vport *);
struct vport *ovs_vport_locate(const char *name); struct vport *ovs_vport_locate(struct net *net, const char *name);
void ovs_vport_get_stats(struct vport *, struct ovs_vport_stats *); void ovs_vport_get_stats(struct vport *, struct ovs_vport_stats *);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment