[ovs-dev] [netlink v2 4/4] datapath: Make adding and attaching a vport a single step.
Ben Pfaff
blp at nicira.com
Fri Sep 24 17:15:45 PDT 2010
For some time now, Open vSwitch datapaths have internally made a
distinction between adding a vport and attaching it to a datapath. Adding
a vport just means to create it, as an entity detached from any datapath.
Attaching it gives it a port number and a datapath. Similarly, a vport
could be detached and deleted separately.
After some study, I think I understand why this distinction exists. It is
because ovs-vswitchd tries to open all the datapath ports before it tries
to create them. However, changing it to create them before it tries to
open them is not difficult, so this commit does this.
The bulk of this commit, however, changes the datapath interface to one
that always creates a vport and attaches it to a datapath in a single step,
and similarly detaches a vport and deletes it in a single step.
Signed-off-by: Ben Pfaff <blp at nicira.com>
---
datapath/datapath.c | 79 +++++---------
datapath/datapath.h | 2 +-
datapath/dp_notify.c | 2 +-
datapath/odp-compat.h | 15 +---
datapath/tunnel.c | 15 ++--
datapath/tunnel.h | 5 +-
datapath/vport-capwap.c | 4 +-
datapath/vport-gre.c | 4 +-
datapath/vport-internal_dev.c | 6 +-
datapath/vport-netdev.c | 4 +-
datapath/vport-patch.c | 19 ++--
datapath/vport.c | 177 +++----------------------------
datapath/vport.h | 19 +---
include/openvswitch/datapath-protocol.h | 31 ++----
include/openvswitch/tunnel.h | 2 +
lib/dpif-linux.c | 71 +++----------
lib/dpif-netdev.c | 34 ++++--
lib/dpif-provider.h | 11 +-
lib/dpif.c | 21 +++--
lib/dpif.h | 5 +-
lib/netdev-provider.h | 1 +
lib/netdev-vport.c | 102 ++++++------------
lib/netdev-vport.h | 3 +
lib/netdev.c | 40 +++----
utilities/ovs-dpctl.8.in | 16 ++--
utilities/ovs-dpctl.c | 53 +++++-----
utilities/ovs-openflowd.c | 2 +-
vswitchd/bridge.c | 81 ++++----------
28 files changed, 262 insertions(+), 562 deletions(-)
diff --git a/datapath/datapath.c b/datapath/datapath.c
index e9f30f8..ae9047b 100644
--- a/datapath/datapath.c
+++ b/datapath/datapath.c
@@ -269,7 +269,7 @@ static int create_dp(int dp_idx, const char __user *devnamep)
/* Set up our datapath device. */
BUILD_BUG_ON(sizeof(internal_dev_port.devname) != sizeof(devname));
strcpy(internal_dev_port.devname, devname);
- internal_dev_port.flags = ODP_PORT_INTERNAL;
+ strcpy(internal_dev_port.type, "internal");
err = new_dp_port(dp, &internal_dev_port, ODPP_LOCAL);
if (err) {
if (err == -EBUSY)
@@ -292,7 +292,7 @@ static int create_dp(int dp_idx, const char __user *devnamep)
return 0;
err_destroy_local_port:
- dp_detach_port(dp->ports[ODPP_LOCAL], 1);
+ dp_detach_port(dp->ports[ODPP_LOCAL]);
err_destroy_table:
tbl_destroy(dp->table, NULL);
err_free_dp:
@@ -313,13 +313,13 @@ static void do_destroy_dp(struct datapath *dp)
list_for_each_entry_safe (p, n, &dp->port_list, node)
if (p->port_no != ODPP_LOCAL)
- dp_detach_port(p, 1);
+ dp_detach_port(p);
dp_sysfs_del_dp(dp);
rcu_assign_pointer(dps[dp->dp_idx], NULL);
- dp_detach_port(dp->ports[ODPP_LOCAL], 1);
+ dp_detach_port(dp->ports[ODPP_LOCAL]);
tbl_destroy(dp->table, flow_free_tbl);
@@ -373,20 +373,12 @@ static int new_dp_port(struct datapath *dp, struct odp_port *odp_port, int port_
struct dp_port *p;
int err;
- vport = vport_locate(odp_port->devname);
- if (!vport) {
- vport_lock();
-
- if (odp_port->flags & ODP_PORT_INTERNAL)
- vport = vport_add(odp_port->devname, "internal", NULL);
- else
- vport = vport_add(odp_port->devname, "netdev", NULL);
-
- vport_unlock();
+ vport_lock();
+ vport = vport_add(odp_port);
+ vport_unlock();
- if (IS_ERR(vport))
- return PTR_ERR(vport);
- }
+ if (IS_ERR(vport))
+ return PTR_ERR(vport);
p = kzalloc(sizeof(*p), GFP_KERNEL);
if (!p)
@@ -428,6 +420,7 @@ static int attach_port(int dp_idx, struct odp_port __user *portp)
if (copy_from_user(&port, portp, sizeof port))
goto out;
port.devname[IFNAMSIZ - 1] = '\0';
+ port.type[VPORT_TYPE_SIZE - 1] = '\0';
rtnl_lock();
dp = get_dp_locked(dp_idx);
@@ -459,7 +452,7 @@ out:
return err;
}
-int dp_detach_port(struct dp_port *p, int may_delete)
+int dp_detach_port(struct dp_port *p)
{
struct vport *vport = p->vport;
int err;
@@ -482,15 +475,9 @@ int dp_detach_port(struct dp_port *p, int may_delete)
/* Then wait until no one is still using it, and destroy it. */
synchronize_rcu();
- if (may_delete) {
- const char *port_type = vport_get_type(vport);
-
- if (!strcmp(port_type, "netdev") || !strcmp(port_type, "internal")) {
- vport_lock();
- vport_del(vport);
- vport_unlock();
- }
- }
+ vport_lock();
+ vport_del(vport);
+ vport_unlock();
kobject_put(&p->kobj);
@@ -518,7 +505,7 @@ static int detach_port(int dp_idx, int port_no)
if (!p)
goto out_unlock_dp;
- err = dp_detach_port(p, 1);
+ err = dp_detach_port(p);
out_unlock_dp:
mutex_unlock(&dp->mutex);
@@ -1487,10 +1474,10 @@ static int put_port(const struct dp_port *p, struct odp_port __user *uop)
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);
rcu_read_unlock();
op.port = p->port_no;
- op.flags = is_internal_vport(p->vport) ? ODP_PORT_INTERNAL : 0;
return copy_to_user(uop, &op, sizeof op) ? -EFAULT : 0;
}
@@ -1684,26 +1671,18 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
err = destroy_dp(dp_idx);
goto exit;
- case ODP_PORT_ATTACH:
+ case ODP_VPORT_ATTACH:
err = attach_port(dp_idx, (struct odp_port __user *)argp);
goto exit;
- case ODP_PORT_DETACH:
+ case ODP_VPORT_DETACH:
err = get_user(port_no, (int __user *)argp);
if (!err)
err = detach_port(dp_idx, port_no);
goto exit;
- case ODP_VPORT_ADD:
- err = vport_user_add((struct odp_vport_add __user *)argp);
- goto exit;
-
case ODP_VPORT_MOD:
- err = vport_user_mod((struct odp_vport_mod __user *)argp);
- goto exit;
-
- case ODP_VPORT_DEL:
- err = vport_user_del((char __user *)argp);
+ err = vport_user_mod((struct odp_port __user *)argp);
goto exit;
case ODP_VPORT_STATS_GET:
@@ -1781,11 +1760,11 @@ static long openvswitch_ioctl(struct file *f, unsigned int cmd,
dp->sflow_probability = sflow_probability;
break;
- case ODP_PORT_QUERY:
+ case ODP_VPORT_QUERY:
err = query_port(dp, (struct odp_port __user *)argp);
break;
- case ODP_PORT_LIST:
+ case ODP_VPORT_LIST:
err = list_ports(dp, (struct odp_portvec __user *)argp);
break;
@@ -2078,9 +2057,9 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned
return openvswitch_ioctl(f, cmd, argp);
case ODP_DP_CREATE:
- case ODP_PORT_ATTACH:
- case ODP_PORT_DETACH:
- case ODP_VPORT_DEL:
+ case ODP_VPORT_ATTACH:
+ case ODP_VPORT_DETACH:
+ case ODP_VPORT_MOD:
case ODP_VPORT_MTU_SET:
case ODP_VPORT_MTU_GET:
case ODP_VPORT_ETHER_SET:
@@ -2094,15 +2073,9 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned
case ODP_GET_LISTEN_MASK:
case ODP_SET_SFLOW_PROBABILITY:
case ODP_GET_SFLOW_PROBABILITY:
- case ODP_PORT_QUERY:
+ case ODP_VPORT_QUERY:
/* Ioctls that just need their pointer argument extended. */
return openvswitch_ioctl(f, cmd, (unsigned long)compat_ptr(argp));
-
- case ODP_VPORT_ADD32:
- return compat_vport_user_add(compat_ptr(argp));
-
- case ODP_VPORT_MOD32:
- return compat_vport_user_mod(compat_ptr(argp));
}
dp = get_dp_locked(dp_idx);
@@ -2111,7 +2084,7 @@ static long openvswitch_compat_ioctl(struct file *f, unsigned int cmd, unsigned
goto exit;
switch (cmd) {
- case ODP_PORT_LIST32:
+ case ODP_VPORT_LIST32:
err = compat_list_ports(dp, compat_ptr(argp));
break;
diff --git a/datapath/datapath.h b/datapath/datapath.h
index f28513b..e9879be 100644
--- a/datapath/datapath.h
+++ b/datapath/datapath.h
@@ -164,7 +164,7 @@ 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 *, int may_delete);
+int dp_detach_port(struct dp_port *);
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 b6bb90e..1843d75 100644
--- a/datapath/dp_notify.c
+++ b/datapath/dp_notify.c
@@ -39,7 +39,7 @@ static int dp_device_event(struct notifier_block *unused, unsigned long event,
switch (event) {
case NETDEV_UNREGISTER:
mutex_lock(&dp->mutex);
- dp_detach_port(p, 1);
+ dp_detach_port(p);
mutex_unlock(&dp->mutex);
break;
diff --git a/datapath/odp-compat.h b/datapath/odp-compat.h
index 3d7b803..261f620 100644
--- a/datapath/odp-compat.h
+++ b/datapath/odp-compat.h
@@ -15,7 +15,7 @@
#include "openvswitch/datapath-protocol.h"
#include <linux/compat.h>
-#define ODP_PORT_LIST32 _IOWR('O', 10, struct compat_odp_portvec)
+#define ODP_VPORT_LIST32 _IOWR('O', 10, struct compat_odp_portvec)
#define ODP_PORT_GROUP_SET32 _IOR('O', 11, struct compat_odp_port_group)
#define ODP_PORT_GROUP_GET32 _IOWR('O', 12, struct compat_odp_port_group)
#define ODP_FLOW_GET32 _IOWR('O', 13, struct compat_odp_flow)
@@ -24,8 +24,6 @@
#define ODP_FLOW_DEL32 _IOWR('O', 17, struct compat_odp_flow)
#define ODP_EXECUTE32 _IOR('O', 18, struct compat_odp_execute)
#define ODP_FLOW_DEL32 _IOWR('O', 17, struct compat_odp_flow)
-#define ODP_VPORT_ADD32 _IOR('O', 21, struct compat_odp_vport_add)
-#define ODP_VPORT_MOD32 _IOR('O', 22, struct compat_odp_vport_mod)
struct compat_odp_portvec {
compat_uptr_t ports;
@@ -67,17 +65,6 @@ struct compat_odp_execute {
compat_uptr_t data;
u32 length;
};
-
-struct compat_odp_vport_add {
- char port_type[VPORT_TYPE_SIZE];
- char devname[16]; /* IFNAMSIZ */
- compat_uptr_t config;
-};
-
-struct compat_odp_vport_mod {
- char devname[16]; /* IFNAMSIZ */
- compat_uptr_t config;
-};
#endif /* CONFIG_COMPAT */
#endif /* odp-compat.h */
diff --git a/datapath/tunnel.c b/datapath/tunnel.c
index 77f976f..61d2988 100644
--- a/datapath/tunnel.c
+++ b/datapath/tunnel.c
@@ -1308,15 +1308,14 @@ out:
return sent_len;
}
-static int set_config(const void __user *uconfig, const struct tnl_ops *tnl_ops,
+static int set_config(__u32 *config, const struct tnl_ops *tnl_ops,
const struct vport *cur_vport,
struct tnl_mutable_config *mutable)
{
const struct vport *old_vport;
const struct tnl_mutable_config *old_mutable;
- if (copy_from_user(&mutable->port_config, uconfig, sizeof(struct tnl_port_config)))
- return -EFAULT;
+ mutable->port_config = *(struct tnl_port_config *)config;
if (mutable->port_config.daddr == 0)
return -EINVAL;
@@ -1352,7 +1351,7 @@ static int set_config(const void __user *uconfig, const struct tnl_ops *tnl_ops,
return 0;
}
-struct vport *tnl_create(const char *name, const void __user *config,
+struct vport *tnl_create(struct odp_port *port,
const struct vport_ops *vport_ops,
const struct tnl_ops *tnl_ops)
{
@@ -1369,7 +1368,7 @@ struct vport *tnl_create(const char *name, const void __user *config,
tnl_vport = tnl_vport_priv(vport);
- strcpy(tnl_vport->name, name);
+ strcpy(tnl_vport->name, port->devname);
tnl_vport->tnl_ops = tnl_ops;
tnl_vport->mutable = kzalloc(sizeof(struct tnl_mutable_config), GFP_KERNEL);
@@ -1384,7 +1383,7 @@ struct vport *tnl_create(const char *name, const void __user *config,
get_random_bytes(&initial_frag_id, sizeof(int));
atomic_set(&tnl_vport->frag_id, initial_frag_id);
- err = set_config(config, tnl_ops, NULL, tnl_vport->mutable);
+ err = set_config(port->config, tnl_ops, NULL, tnl_vport->mutable);
if (err)
goto error_free_mutable;
@@ -1409,7 +1408,7 @@ error:
return ERR_PTR(err);
}
-int tnl_modify(struct vport *vport, const void __user *config)
+int tnl_modify(struct vport *vport, struct odp_port *port)
{
struct tnl_vport *tnl_vport = tnl_vport_priv(vport);
struct tnl_mutable_config *mutable;
@@ -1421,7 +1420,7 @@ int tnl_modify(struct vport *vport, const void __user *config)
goto error;
}
- err = set_config(config, tnl_vport->tnl_ops, vport, mutable);
+ err = set_config(port->config, tnl_vport->tnl_ops, vport, mutable);
if (err)
goto error_free;
diff --git a/datapath/tunnel.h b/datapath/tunnel.h
index 8ffb7bf..66b8c9e 100644
--- a/datapath/tunnel.h
+++ b/datapath/tunnel.h
@@ -184,10 +184,9 @@ struct tnl_vport {
#endif
};
-struct vport *tnl_create(const char *name, const void __user *config,
- const struct vport_ops *,
+struct vport *tnl_create(struct odp_port *, const struct vport_ops *,
const struct tnl_ops *);
-int tnl_modify(struct vport *, const void __user *config);
+int tnl_modify(struct vport *, struct odp_port *);
int tnl_destroy(struct vport *);
int tnl_set_mtu(struct vport *vport, int mtu);
int tnl_set_addr(struct vport *vport, const unsigned char *addr);
diff --git a/datapath/vport-capwap.c b/datapath/vport-capwap.c
index bf1465f..b548323 100644
--- a/datapath/vport-capwap.c
+++ b/datapath/vport-capwap.c
@@ -220,9 +220,9 @@ struct tnl_ops capwap_tnl_ops = {
.update_header = capwap_update_header,
};
-static struct vport *capwap_create(const char *name, const void __user *config)
+static struct vport *capwap_create(struct odp_port *port)
{
- return tnl_create(name, config, &capwap_vport_ops, &capwap_tnl_ops);
+ return tnl_create(port, &capwap_vport_ops, &capwap_tnl_ops);
}
/* Random value. Irrelevant as long as it's not 0 since we set the handler. */
diff --git a/datapath/vport-gre.c b/datapath/vport-gre.c
index be8fb53..aa7df30 100644
--- a/datapath/vport-gre.c
+++ b/datapath/vport-gre.c
@@ -340,9 +340,9 @@ struct tnl_ops gre_tnl_ops = {
.update_header = gre_update_header,
};
-static struct vport *gre_create(const char *name, const void __user *config)
+static struct vport *gre_create(struct odp_port *port)
{
- return tnl_create(name, config, &gre_vport_ops, &gre_tnl_ops);
+ return tnl_create(port, &gre_vport_ops, &gre_tnl_ops);
}
static struct net_protocol gre_protocol_handlers = {
diff --git a/datapath/vport-internal_dev.c b/datapath/vport-internal_dev.c
index 514d00c..7c6b4d7 100644
--- a/datapath/vport-internal_dev.c
+++ b/datapath/vport-internal_dev.c
@@ -200,8 +200,7 @@ static void do_setup(struct net_device *netdev)
vport_gen_rand_ether_addr(netdev->dev_addr);
}
-static struct vport *internal_dev_create(const char *name,
- const void __user *config)
+static struct vport *internal_dev_create(struct odp_port *port)
{
struct vport *vport;
struct netdev_vport *netdev_vport;
@@ -216,7 +215,8 @@ static struct vport *internal_dev_create(const char *name,
netdev_vport = netdev_vport_priv(vport);
- netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev), name, do_setup);
+ netdev_vport->dev = alloc_netdev(sizeof(struct internal_dev),
+ port->devname, do_setup);
if (!netdev_vport->dev) {
err = -ENOMEM;
goto error_free_vport;
diff --git a/datapath/vport-netdev.c b/datapath/vport-netdev.c
index f6709e2..f6d4945 100644
--- a/datapath/vport-netdev.c
+++ b/datapath/vport-netdev.c
@@ -88,7 +88,7 @@ static void netdev_exit(void)
}
#endif
-static struct vport *netdev_create(const char *name, const void __user *config)
+static struct vport *netdev_create(struct odp_port *port)
{
struct vport *vport;
struct netdev_vport *netdev_vport;
@@ -102,7 +102,7 @@ static struct vport *netdev_create(const char *name, const void __user *config)
netdev_vport = netdev_vport_priv(vport);
- netdev_vport->dev = dev_get_by_name(&init_net, name);
+ netdev_vport->dev = dev_get_by_name(&init_net, port->devname);
if (!netdev_vport->dev) {
err = -ENODEV;
goto error_free_vport;
diff --git a/datapath/vport-patch.c b/datapath/vport-patch.c
index 62fd71f..d7316ca 100644
--- a/datapath/vport-patch.c
+++ b/datapath/vport-patch.c
@@ -83,17 +83,12 @@ 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, __u32 *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, (char *)config, IFNAMSIZ);
if (!strcmp(patch_vport->name, peer_name))
return -EINVAL;
@@ -109,7 +104,7 @@ static int set_config(struct vport *vport, const void __user *uconfig)
return 0;
}
-static struct vport *patch_create(const char *name, const void __user *config)
+static struct vport *patch_create(struct odp_port *port)
{
struct vport *vport;
struct patch_vport *patch_vport;
@@ -123,9 +118,9 @@ static struct vport *patch_create(const char *name, const void __user *config)
patch_vport = patch_vport_priv(vport);
- strcpy(patch_vport->name, name);
+ strcpy(patch_vport->name, port->devname);
- err = set_config(vport, config);
+ err = set_config(vport, port->config);
if (err)
goto error_free_vport;
@@ -149,9 +144,9 @@ 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);
+ return set_config(vport, port->config);
}
static int patch_destroy(struct vport *vport)
diff --git a/datapath/vport.c b/datapath/vport.c
index 6c8eb08..7c38e81 100644
--- a/datapath/vport.c
+++ b/datapath/vport.c
@@ -177,88 +177,24 @@ void vport_exit(void)
kfree(dev_table);
}
-static int do_vport_add(struct odp_vport_add *vport_config)
-{
- struct vport *vport;
- int err = 0;
-
- vport_config->port_type[VPORT_TYPE_SIZE - 1] = '\0';
- vport_config->devname[IFNAMSIZ - 1] = '\0';
-
- rtnl_lock();
-
- vport = vport_locate(vport_config->devname);
- if (vport) {
- err = -EBUSY;
- goto out;
- }
-
- vport_lock();
- vport = vport_add(vport_config->devname, vport_config->port_type,
- vport_config->config);
- vport_unlock();
-
- if (IS_ERR(vport))
- err = PTR_ERR(vport);
-
-out:
- rtnl_unlock();
- return err;
-}
-
-/**
- * vport_user_add - add vport device (for userspace callers)
- *
- * @uvport_config: New port configuration.
- *
- * Creates a new vport with the specified configuration (which is dependent
- * on device type). This function is for userspace callers and assumes no
- * locks are held.
- */
-int vport_user_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_user_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
-
-static int do_vport_mod(struct odp_vport_mod *vport_config)
+static int do_vport_mod(struct odp_port *port)
{
struct vport *vport;
int err;
- vport_config->devname[IFNAMSIZ - 1] = '\0';
+ port->devname[IFNAMSIZ - 1] = '\0';
rtnl_lock();
- vport = vport_locate(vport_config->devname);
+ vport = vport_locate(port->devname);
if (!vport) {
err = -ENODEV;
goto out;
}
vport_lock();
- err = vport_mod(vport, vport_config->config);
+ err = vport_mod(vport, port);
vport_unlock();
out:
@@ -269,98 +205,20 @@ out:
/**
* vport_user_mod - modify existing vport device (for userspace callers)
*
- * @uvport_config: New configuration for vport
+ * @uport: New configuration for vport
*
* Modifies an existing device with the specified configuration (which is
* dependent on device type). This function is for userspace callers and
* assumes no locks are held.
*/
-int vport_user_mod(const struct odp_vport_mod __user *uvport_config)
+int vport_user_mod(const struct odp_port __user *uport)
{
- struct odp_vport_mod vport_config;
+ struct odp_port port;
- if (copy_from_user(&vport_config, uvport_config, sizeof(struct odp_vport_mod)))
+ if (copy_from_user(&port, uport, sizeof(port)))
return -EFAULT;
- return do_vport_mod(&vport_config);
-}
-
-#ifdef CONFIG_COMPAT
-int compat_vport_user_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_user_del - delete existing vport device (for userspace callers)
- *
- * @udevname: Name of device to delete
- *
- * Deletes the specified device. Detaches the device from a datapath first
- * if it is attached. Deleting the device will fail if it does not exist or it
- * is the datapath local port. It is also possible to fail for less obvious
- * reasons, such as lack of memory. This function is for userspace callers and
- * assumes no locks are held.
- */
-int vport_user_del(const char __user *udevname)
-{
- char devname[IFNAMSIZ];
- struct vport *vport;
- struct dp_port *dp_port;
- int err = 0;
- int retval;
-
- retval = strncpy_from_user(devname, udevname, IFNAMSIZ);
- if (retval < 0)
- return -EFAULT;
- else if (retval >= IFNAMSIZ)
- return -ENAMETOOLONG;
-
- rtnl_lock();
-
- vport = vport_locate(devname);
- if (!vport) {
- err = -ENODEV;
- goto out;
- }
-
- dp_port = vport_get_dp_port(vport);
- if (dp_port) {
- struct datapath *dp = dp_port->dp;
-
- mutex_lock(&dp->mutex);
-
- if (!strcmp(dp_name(dp), devname)) {
- err = -EINVAL;
- goto dp_port_out;
- }
-
- err = dp_detach_port(dp_port, 0);
-
-dp_port_out:
- mutex_unlock(&dp->mutex);
-
- if (err)
- goto out;
- }
-
- vport_lock();
- err = vport_del(vport);
- vport_unlock();
-
-out:
- rtnl_unlock();
- return err;
+ return do_vport_mod(&port);
}
/**
@@ -703,15 +561,12 @@ void vport_free(struct vport *vport)
/**
* vport_add - add vport device (for kernel callers)
*
- * @name: Name of new device.
- * @type: Type of new device (to be matched against types in registered vport
- * ops).
- * @config: Device type specific configuration. Userspace pointer.
+ * @port: new port information
*
* Creates a new vport with the specified configuration (which is dependent
* on device type). Both RTNL and vport locks must be held.
*/
-struct vport *vport_add(const char *name, const char *type, const void __user *config)
+struct vport *vport_add(struct odp_port *port)
{
struct vport *vport;
int err = 0;
@@ -721,8 +576,8 @@ struct vport *vport_add(const char *name, const char *type, const void __user *c
ASSERT_VPORT();
for (i = 0; i < n_vport_types; i++) {
- if (!strcmp(vport_ops_list[i]->type, type)) {
- vport = vport_ops_list[i]->create(name, config);
+ if (!strcmp(vport_ops_list[i]->type, port->type)) {
+ vport = vport_ops_list[i]->create(port);
if (IS_ERR(vport)) {
err = PTR_ERR(vport);
goto out;
@@ -743,18 +598,18 @@ out:
* vport_mod - modify existing vport device (for kernel callers)
*
* @vport: vport to modify.
- * @config: Device type specific configuration. Userspace pointer.
+ * @port: New configuration.
*
* Modifies an existing device with the specified configuration (which is
* dependent on device type). Both RTNL and vport locks must be held.
*/
-int vport_mod(struct vport *vport, const void __user *config)
+int vport_mod(struct vport *vport, struct odp_port *port)
{
ASSERT_RTNL();
ASSERT_VPORT();
if (vport->ops->modify)
- return vport->ops->modify(vport, config);
+ return vport->ops->modify(vport, port);
else
return -EOPNOTSUPP;
}
diff --git a/datapath/vport.h b/datapath/vport.h
index 30b0cc6..653e2fa 100644
--- a/datapath/vport.h
+++ b/datapath/vport.h
@@ -23,15 +23,9 @@ struct dp_port;
/* The following definitions are for users of the vport subsytem: */
-int vport_user_add(const struct odp_vport_add __user *);
-int vport_user_mod(const struct odp_vport_mod __user *);
+int vport_user_mod(const struct odp_port __user *);
int vport_user_del(const char __user *udevname);
-#ifdef CONFIG_COMPAT
-int compat_vport_user_add(struct compat_odp_vport_add __user *);
-int compat_vport_user_mod(struct compat_odp_vport_mod __user *);
-#endif
-
int vport_user_stats_get(struct odp_vport_stats_req __user *);
int vport_user_stats_set(struct odp_vport_stats_req __user *);
int vport_user_ether_get(struct odp_vport_ether __user *);
@@ -45,8 +39,8 @@ void vport_unlock(void);
int vport_init(void);
void vport_exit(void);
-struct vport *vport_add(const char *name, const char *type, const void __user *config);
-int vport_mod(struct vport *, const void __user *config);
+struct vport *vport_add(struct odp_port *);
+int vport_mod(struct vport *, struct odp_port *);
int vport_del(struct vport *);
struct vport *vport_locate(const char *name);
@@ -126,8 +120,7 @@ struct vport {
* failure of this function will cause the module to not load. If the flag is
* not set and initialzation fails then no vports of this type can be created.
* @exit: Called at module unload.
- * @create: Create a new vport called 'name' with vport type specific
- * configuration 'config' (which must be copied from userspace before use). On
+ * @create: Create a new vport with configuration given in 'port'. On
* success must allocate a new vport using vport_alloc().
* @modify: Modify the configuration of an existing vport. May be null if
* modification is not supported.
@@ -168,8 +161,8 @@ struct vport_ops {
void (*exit)(void);
/* Called with RTNL lock. */
- struct vport *(*create)(const char *name, const void __user *config);
- int (*modify)(struct vport *, const void __user *config);
+ struct vport *(*create)(struct odp_port *port);
+ int (*modify)(struct vport *, struct odp_port *);
int (*destroy)(struct vport *);
int (*attach)(struct vport *);
diff --git a/include/openvswitch/datapath-protocol.h b/include/openvswitch/datapath-protocol.h
index 5759f1e..4d61dcc 100644
--- a/include/openvswitch/datapath-protocol.h
+++ b/include/openvswitch/datapath-protocol.h
@@ -74,10 +74,10 @@
#define ODP_GET_LISTEN_MASK _IOW('O', 5, int)
#define ODP_SET_LISTEN_MASK _IOR('O', 6, int)
-#define ODP_PORT_ATTACH _IOR('O', 7, struct odp_port)
-#define ODP_PORT_DETACH _IOR('O', 8, int)
-#define ODP_PORT_QUERY _IOWR('O', 9, struct odp_port)
-#define ODP_PORT_LIST _IOWR('O', 10, struct odp_portvec)
+#define ODP_VPORT_ATTACH _IOR('O', 7, struct odp_port)
+#define ODP_VPORT_DETACH _IOR('O', 8, int)
+#define ODP_VPORT_QUERY _IOWR('O', 9, struct odp_port)
+#define ODP_VPORT_LIST _IOWR('O', 10, struct odp_portvec)
#define ODP_PORT_GROUP_SET _IOR('O', 11, struct odp_port_group)
#define ODP_PORT_GROUP_GET _IOWR('O', 12, struct odp_port_group)
@@ -93,9 +93,7 @@
#define ODP_SET_SFLOW_PROBABILITY _IOR('O', 19, int)
#define ODP_GET_SFLOW_PROBABILITY _IOW('O', 20, int)
-#define ODP_VPORT_ADD _IOR('O', 21, struct odp_vport_add)
-#define ODP_VPORT_MOD _IOR('O', 22, struct odp_vport_mod)
-#define ODP_VPORT_DEL _IO('O', 23)
+#define ODP_VPORT_MOD _IOR('O', 22, struct odp_port)
#define ODP_VPORT_STATS_GET _IOWR('O', 24, struct odp_vport_stats_req)
#define ODP_VPORT_ETHER_GET _IOWR('O', 25, struct odp_vport_ether)
#define ODP_VPORT_ETHER_SET _IOW('O', 26, struct odp_vport_ether)
@@ -185,12 +183,15 @@ struct odp_sflow_sample_header {
uint32_t n_actions;
};
-#define ODP_PORT_INTERNAL (1 << 0) /* This port is simulated. */
+#define VPORT_TYPE_SIZE 16
+#define VPORT_CONFIG_SIZE 32
struct odp_port {
char devname[16]; /* IFNAMSIZ */
+ char type[VPORT_TYPE_SIZE];
uint16_t port;
- uint16_t flags;
+ uint16_t reserved1;
uint32_t reserved2;
+ uint32_t config[VPORT_CONFIG_SIZE / 4]; /* type-specific configuration */
};
struct odp_portvec {
@@ -390,18 +391,6 @@ struct odp_execute {
uint32_t length;
};
-#define VPORT_TYPE_SIZE 16
-struct odp_vport_add {
- char port_type[VPORT_TYPE_SIZE];
- char devname[16]; /* IFNAMSIZ */
- void *config;
-};
-
-struct odp_vport_mod {
- char devname[16]; /* IFNAMSIZ */
- void *config;
-};
-
struct odp_vport_stats {
uint64_t rx_packets;
uint64_t tx_packets;
diff --git a/include/openvswitch/tunnel.h b/include/openvswitch/tunnel.h
index dd700d0..e7d3fce 100644
--- a/include/openvswitch/tunnel.h
+++ b/include/openvswitch/tunnel.h
@@ -41,6 +41,7 @@
#define OPENVSWITCH_TUNNEL_H 1
#include <linux/types.h>
+#include "openvswitch/datapath-protocol.h"
#define TNL_F_CSUM (1 << 1) /* Checksum packets. */
#define TNL_F_IN_KEY_MATCH (1 << 2) /* Store the key in tun_id to match in flow table. */
@@ -50,6 +51,7 @@
#define TNL_F_PMTUD (1 << 6) /* Enable path MTU discovery. */
#define TNL_F_HDR_CACHE (1 << 7) /* Enable tunnel header caching. */
+/* This goes in the "config" member of struct odp_port for tunnel vports. */
struct tnl_port_config {
__u32 flags;
__be32 saddr;
diff --git a/lib/dpif-linux.c b/lib/dpif-linux.c
index 635fe94..b4837fd 100644
--- a/lib/dpif-linux.c
+++ b/lib/dpif-linux.c
@@ -35,6 +35,7 @@
#include "dpif-provider.h"
#include "netdev.h"
+#include "netdev-vport.h"
#include "ofpbuf.h"
#include "poll-loop.h"
#include "rtnetlink.h"
@@ -156,7 +157,7 @@ dpif_linux_open(const char *name, const char *type OVS_UNUSED, bool create,
* getting the local port's name. */
memset(&port, 0, sizeof port);
port.port = ODPP_LOCAL;
- if (ioctl(dpif->fd, ODP_PORT_QUERY, &port)) {
+ if (ioctl(dpif->fd, ODP_VPORT_QUERY, &port)) {
error = errno;
if (error != ENODEV) {
VLOG_WARN("%s: probe returned unexpected error: %s",
@@ -195,28 +196,6 @@ dpif_linux_get_all_names(const struct dpif *dpif_, struct svec *all_names)
static int
dpif_linux_destroy(struct dpif *dpif_)
{
- struct odp_port *ports;
- size_t n_ports;
- int err;
- int i;
-
- err = dpif_port_list(dpif_, &ports, &n_ports);
- if (err) {
- return err;
- }
-
- for (i = 0; i < n_ports; i++) {
- if (ports[i].port != ODPP_LOCAL) {
- err = do_ioctl(dpif_, ODP_VPORT_DEL, ports[i].devname);
- if (err) {
- VLOG_WARN_RL(&error_rl, "%s: error deleting port %s (%s)",
- dpif_name(dpif_), ports[i].devname, strerror(err));
- }
- }
- }
-
- free(ports);
-
return do_ioctl(dpif_, ODP_DP_DESTROY, NULL);
}
@@ -248,47 +227,27 @@ dpif_linux_set_drop_frags(struct dpif *dpif_, bool drop_frags)
}
static int
-dpif_linux_port_add(struct dpif *dpif_, const char *devname, uint16_t flags,
- uint16_t *port_no)
+dpif_linux_port_add(struct dpif *dpif, const char *devname, const char *type,
+ const struct shash *args, uint16_t *port_nop)
{
struct odp_port port;
int error;
- memset(&port, 0, sizeof port);
- strncpy(port.devname, devname, sizeof port.devname);
- port.flags = flags;
- error = do_ioctl(dpif_, ODP_PORT_ATTACH, &port);
+ error = netdev_vport_parse_config(&port, devname, type, args);
if (!error) {
- *port_no = port.port;
+ error = do_ioctl(dpif, ODP_VPORT_ATTACH, &port);
+ if (!error) {
+ *port_nop = port.port;
+ }
}
return error;
}
static int
-dpif_linux_port_del(struct dpif *dpif_, uint16_t port_no)
+dpif_linux_port_del(struct dpif *dpif_, uint16_t port_no_)
{
- int tmp = port_no;
- int err;
- struct odp_port port;
-
- err = dpif_port_query_by_number(dpif_, port_no, &port);
- if (err) {
- return err;
- }
-
- err = do_ioctl(dpif_, ODP_PORT_DETACH, &tmp);
- if (err) {
- return err;
- }
-
- if (!netdev_is_open(port.devname)) {
- /* Try deleting the port if no one has it open. This shouldn't
- * actually be necessary unless the config changed while we weren't
- * running but it won't hurt anything if the port is already gone. */
- do_ioctl(dpif_, ODP_VPORT_DEL, port.devname);
- }
-
- return 0;
+ int port_no = port_no_; /* Kernel expects an "int". */
+ return do_ioctl(dpif_, ODP_VPORT_DETACH, &port_no);
}
static int
@@ -297,7 +256,7 @@ dpif_linux_port_query_by_number(const struct dpif *dpif_, uint16_t port_no,
{
memset(port, 0, sizeof *port);
port->port = port_no;
- return do_ioctl(dpif_, ODP_PORT_QUERY, port);
+ return do_ioctl(dpif_, ODP_VPORT_QUERY, port);
}
static int
@@ -306,7 +265,7 @@ dpif_linux_port_query_by_name(const struct dpif *dpif_, const char *devname,
{
memset(port, 0, sizeof *port);
strncpy(port->devname, devname, sizeof port->devname);
- return do_ioctl(dpif_, ODP_PORT_QUERY, port);
+ return do_ioctl(dpif_, ODP_VPORT_QUERY, port);
}
static int
@@ -323,7 +282,7 @@ dpif_linux_port_list(const struct dpif *dpif_, struct odp_port *ports, int n)
pv.ports = ports;
pv.n_ports = n;
- error = do_ioctl(dpif_, ODP_PORT_LIST, &pv);
+ error = do_ioctl(dpif_, ODP_VPORT_LIST, &pv);
return error ? -error : pv.n_ports;
}
diff --git a/lib/dpif-netdev.c b/lib/dpif-netdev.c
index 3975b5a..550a898 100644
--- a/lib/dpif-netdev.c
+++ b/lib/dpif-netdev.c
@@ -43,6 +43,7 @@
#include "packets.h"
#include "poll-loop.h"
#include "queue.h"
+#include "shash.h"
#include "timeval.h"
#include "util.h"
#include "vlog.h"
@@ -90,7 +91,7 @@ struct dp_netdev_port {
int port_no; /* Index into dp_netdev's 'ports'. */
struct list node; /* Element in dp_netdev's 'port_list'. */
struct netdev *netdev;
- bool internal; /* Internal port (as ODP_PORT_INTERNAL)? */
+ bool internal; /* Internal port? */
};
/* A flow in dp_netdev's 'flow_table'. */
@@ -131,7 +132,8 @@ static int get_port_by_name(struct dp_netdev *, const char *devname,
struct dp_netdev_port **portp);
static void dp_netdev_free(struct dp_netdev *);
static void dp_netdev_flow_flush(struct dp_netdev *);
-static int do_add_port(struct dp_netdev *, const char *devname, uint16_t flags,
+static int do_add_port(struct dp_netdev *, const char *devname,
+ const char *type, const struct shash *args,
uint16_t port_no);
static int do_del_port(struct dp_netdev *, uint16_t port_no);
static int dp_netdev_output_control(struct dp_netdev *, const struct ofpbuf *,
@@ -234,7 +236,7 @@ create_dp_netdev(const char *name, int dp_idx, struct dpif **dpifp)
dp->groups[i].group = i;
}
list_init(&dp->port_list);
- error = do_add_port(dp, name, ODP_PORT_INTERNAL, ODPP_LOCAL);
+ error = do_add_port(dp, name, "internal", NULL, ODPP_LOCAL);
if (error) {
dp_netdev_free(dp);
return ENODEV;
@@ -358,17 +360,29 @@ dpif_netdev_set_drop_frags(struct dpif *dpif, bool drop_frags)
}
static int
-do_add_port(struct dp_netdev *dp, const char *devname, uint16_t flags,
- uint16_t port_no)
+do_add_port(struct dp_netdev *dp, const char *devname, const char *type,
+ const struct shash *args, uint16_t port_no)
{
- bool internal = (flags & ODP_PORT_INTERNAL) != 0;
struct dp_netdev_port *port;
struct netdev_options netdev_options;
struct netdev *netdev;
+ bool internal;
int mtu;
int error;
/* XXX reject devices already in some dp_netdev. */
+ if (type[0] == '\0' || !strcmp(type, "system")) {
+ internal = false;
+ } else if (!strcmp(type, "internal")) {
+ internal = true;
+ } else {
+ VLOG_WARN("%s: unsupported port type %s", devname, type);
+ return EINVAL;
+ }
+
+ if (args && !shash_is_empty(args)) {
+ VLOG_WARN("%s: arguments for %s ports should be empty", devname, type);
+ }
/* Open and validate network device. */
memset(&netdev_options, 0, sizeof netdev_options);
@@ -410,8 +424,8 @@ do_add_port(struct dp_netdev *dp, const char *devname, uint16_t flags,
}
static int
-dpif_netdev_port_add(struct dpif *dpif, const char *devname, uint16_t flags,
- uint16_t *port_nop)
+dpif_netdev_port_add(struct dpif *dpif, const char *devname, const char *type,
+ const struct shash *args, uint16_t *port_nop)
{
struct dp_netdev *dp = get_dp_netdev(dpif);
int port_no;
@@ -419,7 +433,7 @@ dpif_netdev_port_add(struct dpif *dpif, const char *devname, uint16_t flags,
for (port_no = 0; port_no < MAX_PORTS; port_no++) {
if (!dp->ports[port_no]) {
*port_nop = port_no;
- return do_add_port(dp, devname, flags, port_no);
+ return do_add_port(dp, devname, type, args, port_no);
}
}
return EFBIG;
@@ -499,7 +513,7 @@ answer_port_query(const struct dp_netdev_port *port, struct odp_port *odp_port)
ovs_strlcpy(odp_port->devname, netdev_get_name(port->netdev),
sizeof odp_port->devname);
odp_port->port = port->port_no;
- odp_port->flags = port->internal ? ODP_PORT_INTERNAL : 0;
+ strcpy(odp_port->type, port->internal ? "internal" : "system");
}
static int
diff --git a/lib/dpif-provider.h b/lib/dpif-provider.h
index 1106db8..308550d 100644
--- a/lib/dpif-provider.h
+++ b/lib/dpif-provider.h
@@ -137,11 +137,12 @@ struct dpif_class {
* meaning is the same as for the get_drop_frags member function. */
int (*set_drop_frags)(struct dpif *dpif, bool drop_frags);
- /* Creates a new port in 'dpif' connected to network device 'devname'.
- * 'flags' is a set of ODP_PORT_* flags. If successful, sets '*port_no'
- * to the new port's port number. */
- int (*port_add)(struct dpif *dpif, const char *devname, uint16_t flags,
- uint16_t *port_no);
+ /* Creates a new port in 'dpif' with the specified 'type' and 'devname'.
+ * 'args' is a set of options to further configure the port; the options
+ * that are accepted varies depending on 'type'. If successful, sets
+ * '*port_no' to the new port's port number. */
+ int (*port_add)(struct dpif *dpif, const char *type, const char *devname,
+ const struct shash *args, uint16_t *port_no);
/* Removes port numbered 'port_no' from 'dpif'. */
int (*port_del)(struct dpif *dpif, uint16_t port_no);
diff --git a/lib/dpif.c b/lib/dpif.c
index 01e905d..66741ce 100644
--- a/lib/dpif.c
+++ b/lib/dpif.c
@@ -428,21 +428,26 @@ dpif_set_drop_frags(struct dpif *dpif, bool drop_frags)
return error;
}
-/* Attempts to add 'devname' as a port on 'dpif', given the combination of
- * ODP_PORT_* flags in 'flags'. If successful, returns 0 and sets '*port_nop'
- * to the new port's port number (if 'port_nop' is non-null). On failure,
- * returns a positive errno value and sets '*port_nop' to UINT16_MAX (if
- * 'port_nop' is non-null). */
+/* Attempts to add 'devname' as a port on 'dpif' with the given 'type' and
+ * 'args'. If successful, returns 0 and sets '*port_nop' to the new port's
+ * port number (if 'port_nop' is non-null). On failure, returns a positive
+ * errno value and sets '*port_nop' to UINT16_MAX (if 'port_nop' is
+ * non-null). */
int
-dpif_port_add(struct dpif *dpif, const char *devname, uint16_t flags,
- uint16_t *port_nop)
+dpif_port_add(struct dpif *dpif, const char *devname, const char *type,
+ const struct shash *args, uint16_t *port_nop)
{
+ static struct shash empty_args = SHASH_INITIALIZER(&empty_args);
uint16_t port_no;
int error;
COVERAGE_INC(dpif_port_add);
- error = dpif->dpif_class->port_add(dpif, devname, flags, &port_no);
+ if (!args) {
+ args = &empty_args;
+ }
+
+ error = dpif->dpif_class->port_add(dpif, devname, type, args, &port_no);
if (!error) {
VLOG_DBG_RL(&dpmsg_rl, "%s: added %s as port %"PRIu16,
dpif_name(dpif), devname, port_no);
diff --git a/lib/dpif.h b/lib/dpif.h
index 1496c22..2ed436a 100644
--- a/lib/dpif.h
+++ b/lib/dpif.h
@@ -31,6 +31,7 @@ extern "C" {
struct dpif;
struct ofpbuf;
+struct shash;
struct svec;
struct dpif_class;
@@ -59,8 +60,8 @@ int dpif_get_dp_stats(const struct dpif *, struct odp_stats *);
int dpif_get_drop_frags(const struct dpif *, bool *drop_frags);
int dpif_set_drop_frags(struct dpif *, bool drop_frags);
-int dpif_port_add(struct dpif *, const char *devname, uint16_t flags,
- uint16_t *port_no);
+int dpif_port_add(struct dpif *, const char *devname, const char *type,
+ const struct shash *args, uint16_t *port_nop);
int dpif_port_del(struct dpif *, uint16_t port_no);
int dpif_port_query_by_number(const struct dpif *, uint16_t port_no,
struct odp_port *);
diff --git a/lib/netdev-provider.h b/lib/netdev-provider.h
index d4ff620..aa369d1 100644
--- a/lib/netdev-provider.h
+++ b/lib/netdev-provider.h
@@ -548,6 +548,7 @@ struct netdev_class {
int netdev_register_provider(const struct netdev_class *);
int netdev_unregister_provider(const char *type);
+const struct netdev_class *netdev_lookup_provider(const char *type);
extern const struct netdev_class netdev_linux_class;
extern const struct netdev_class netdev_tap_class;
diff --git a/lib/netdev-vport.c b/lib/netdev-vport.c
index 90eb741..ffbb4b3 100644
--- a/lib/netdev-vport.c
+++ b/lib/netdev-vport.c
@@ -48,15 +48,9 @@ struct netdev_vport {
struct netdev netdev;
};
-struct vport_info {
- const char *devname;
- const char *type;
- void *config;
-};
-
struct vport_class {
- const struct netdev_class netdev_class;
- int (*parse_config)(struct vport_info *port, const struct shash *args);
+ struct netdev_class netdev_class;
+ int (*parse_config)(struct odp_port *port, const struct shash *args);
};
static struct shash netdev_vport_notifiers =
@@ -97,29 +91,34 @@ netdev_vport_cast(const struct netdev *netdev)
return CONTAINER_OF(netdev, struct netdev_vport, netdev);
}
-static int
-netdev_vport_parse_config(const struct netdev_class *netdev_class,
- const char *name, const struct shash *args,
- void **configp)
+int
+netdev_vport_parse_config(struct odp_port *port, const char *name,
+ const char *type, const struct shash *args)
{
- const struct vport_class *c = vport_class_cast(netdev_class);
- if (c->parse_config) {
- struct vport_info info;
- int error;
-
- info.devname = name;
- info.type = netdev_class->type;
- error = (c->parse_config)(&info, args);
- *configp = info.config;
- return error;
+ memset(port, 0, sizeof *port);
+ strncpy(port->devname, name, sizeof port->devname);
+
+ if (type[0] == '\0' || !strcmp(type, "system")) {
+ strncpy(port->type, "netdev", sizeof port->type);
} else {
- if (!shash_is_empty(args)) {
- VLOG_WARN("%s: arguments for %s vports should be empty",
- name, netdev_class->type);
+ const struct netdev_class *netdev_class;
+ const struct vport_class *class;
+
+ strncpy(port->type, type, sizeof port->type);
+
+ netdev_class = netdev_lookup_provider(port->type);
+ class = (netdev_class && is_vport_class(netdev_class)
+ ? vport_class_cast(netdev_class)
+ : NULL);
+
+ if (!class) {
+ VLOG_WARN("%s: unsupported port type \"%s\"", name, type);
+ return EINVAL;
+ } else if (class->parse_config) {
+ return (class->parse_config)(port, args);
}
- *configp = NULL;
- return 0;
}
+ return 0;
}
static int
@@ -127,39 +126,12 @@ netdev_vport_create(const struct netdev_class *class, const char *name,
const struct shash *args OVS_UNUSED,
struct netdev_dev **netdev_devp)
{
- int err;
- struct odp_vport_add ova;
struct netdev_dev_vport *netdev_dev;
- ovs_strlcpy(ova.port_type, class->type, sizeof ova.port_type);
- ovs_strlcpy(ova.devname, name, sizeof ova.devname);
- err = netdev_vport_parse_config(class, name, args, &ova.config);
- if (err) {
- return err;
- }
-
- err = netdev_vport_do_ioctl(ODP_VPORT_ADD, &ova);
- free(ova.config);
-
- if (err == EBUSY) {
- VLOG_WARN("%s: destroying existing device", name);
-
- err = netdev_vport_do_ioctl(ODP_VPORT_DEL, ova.devname);
- if (err) {
- return err;
- }
-
- err = netdev_vport_do_ioctl(ODP_VPORT_ADD, &ova);
- }
-
- if (err) {
- return err;
- }
-
netdev_dev = xmalloc(sizeof *netdev_dev);
netdev_dev_init(&netdev_dev->netdev_dev, name, class);
-
*netdev_devp = &netdev_dev->netdev_dev;
+
return 0;
}
@@ -196,20 +168,16 @@ netdev_vport_reconfigure(struct netdev_dev *netdev_dev,
const struct shash *args)
{
const char *name = netdev_dev_get_name(netdev_dev);
- struct odp_vport_mod ovm;
- void *config;
+ const char *type = netdev_dev_get_type(netdev_dev);
+ struct odp_port port;
int err;
- ovs_strlcpy(ovm.devname, name, sizeof ovm.devname);
- err = netdev_vport_parse_config(netdev_dev_get_class(netdev_dev), name,
- args, &config);
+ err = netdev_vport_parse_config(&port, name, type, args);
if (err) {
return err;
}
- err = netdev_vport_do_ioctl(ODP_VPORT_MOD, &ovm);
- free(config);
- return err;
+ return netdev_vport_do_ioctl(ODP_VPORT_MOD, &port);
}
static int
@@ -457,7 +425,7 @@ netdev_vport_poll_notify(const struct netdev *netdev)
/* Code specific to individual vport types. */
static int
-parse_tunnel_config(struct vport_info *port, const struct shash *args)
+parse_tunnel_config(struct odp_port *port, const struct shash *args)
{
const char *name = port->devname;
bool is_gre = !strcmp(port->type, "gre");
@@ -466,7 +434,7 @@ parse_tunnel_config(struct vport_info *port, const struct shash *args)
bool ipsec_ip_set = false;
bool ipsec_mech_set = false;
- config = port->config = xzalloc(sizeof *config);
+ config = (struct tnl_port_config *) port->config;
config->flags |= TNL_F_PMTUD;
config->flags |= TNL_F_HDR_CACHE;
@@ -556,7 +524,7 @@ parse_tunnel_config(struct vport_info *port, const struct shash *args)
}
static int
-parse_patch_config(struct vport_info *port, const struct shash *args)
+parse_patch_config(struct odp_port *port, const struct shash *args)
{
const char *name = port->devname;
const char *peer;
@@ -582,7 +550,7 @@ parse_patch_config(struct vport_info *port, const struct shash *args)
return EINVAL;
}
- port->config = xstrdup(peer);
+ strncpy((char *) port->config, peer, sizeof port->config);
return 0;
}
diff --git a/lib/netdev-vport.h b/lib/netdev-vport.h
index 0898ec0..51584af 100644
--- a/lib/netdev-vport.h
+++ b/lib/netdev-vport.h
@@ -23,6 +23,9 @@ struct odp_port;
struct shash;
void netdev_vport_register(void);
+int netdev_vport_parse_config(struct odp_port *, const char *devname,
+ const char *type, const struct shash *args);
+
int netdev_vport_get_stats(const struct netdev *, struct netdev_stats *);
int netdev_vport_set_stats(struct netdev *, const struct netdev_stats *);
diff --git a/lib/netdev.c b/lib/netdev.c
index ed2fe9e..6ef2032 100644
--- a/lib/netdev.c
+++ b/lib/netdev.c
@@ -163,6 +163,12 @@ netdev_unregister_provider(const char *type)
return 0;
}
+const struct netdev_class *
+netdev_lookup_provider(const char *type)
+{
+ return shash_find_data(&netdev_classes, type && type[0] ? type : "system");
+}
+
/* Clears 'types' and enumerates the types of all currently registered netdev
* providers into it. The caller must first initialize the svec. */
void
@@ -248,25 +254,6 @@ update_device_args(struct netdev_dev *dev, const struct shash *args)
qsort(dev->args, dev->n_args, sizeof *dev->args, compare_args);
}
-static int
-create_device(struct netdev_options *options, struct netdev_dev **netdev_devp)
-{
- struct netdev_class *netdev_class;
-
- if (!options->type || strlen(options->type) == 0) {
- /* Default to system. */
- options->type = "system";
- }
-
- netdev_class = shash_find_data(&netdev_classes, options->type);
- if (!netdev_class) {
- return EAFNOSUPPORT;
- }
-
- return netdev_class->create(netdev_class, options->name, options->args,
- netdev_devp);
-}
-
/* Opens the network device named 'name' (e.g. "eth0") and returns zero if
* successful, otherwise a positive errno value. On success, sets '*netdevp'
* to the new network device, otherwise to null.
@@ -295,12 +282,17 @@ netdev_open(struct netdev_options *options, struct netdev **netdevp)
netdev_dev = shash_find_data(&netdev_dev_shash, options->name);
if (!netdev_dev) {
- error = create_device(options, &netdev_dev);
+ const struct netdev_class *class;
+
+ class = netdev_lookup_provider(options->type);
+ if (!class) {
+ VLOG_WARN("could not create netdev %s of unknown type %s",
+ options->name, options->type);
+ return EAFNOSUPPORT;
+ }
+ error = class->create(class, options->name, options->args,
+ &netdev_dev);
if (error) {
- if (error == EAFNOSUPPORT) {
- VLOG_WARN("could not create netdev %s of unknown type %s",
- options->name, options->type);
- }
return error;
}
update_device_args(netdev_dev, options->args);
diff --git a/utilities/ovs-dpctl.8.in b/utilities/ovs-dpctl.8.in
index b7965bc..dd4ed33 100644
--- a/utilities/ovs-dpctl.8.in
+++ b/utilities/ovs-dpctl.8.in
@@ -21,10 +21,8 @@ host's other network devices. To intercept and process traffic on a
given network device, use the \fBadd\-if\fR command to explicitly add
that network device to the datapath.
.PP
-Do not use \fBovs\-dpctl\fR commands to modify datapaths if
-\fBovs\-vswitchd\fR(8) is in use. Instead, modify the
-\fBovs\-vswitchd\fR configuration file and send \fBSIGHUP\fR to the
-\fBovs\-vswitchd\fR process.
+If \fBovs\-vswitchd\fR(8) is in use, use \fBovs\-vsctl\fR(8) instead
+of \fBovs\-dpctl\fR.
.PP
Most \fBovs\-dpctl\fR commands that work with datapaths take an argument
that specifies the name of the datapath, in one of the following
@@ -66,10 +64,14 @@ A \fInetdev\fR may be followed by a comma-separated list of options.
The following options are currently supported:
.
.RS
-.IP "\fBinternal\fR"
-Instead of attaching an existing \fInetdev\fR, creates an internal
-port (analogous to the local port) with that name.
+.IP "\fBtype=\fItype\fR"
+Specifies the type of port to add. The default type is \fBsystem\fR.
+.IP "\fIkey\fB=\fIvalue\fR"
+Adds an arbitrary key-value option to the port's configuration.
.RE
+.IP
+\fBovs\-vswitchd.conf.db\fR(5) documents the available port types and
+options.
.
.TP
\fBdel\-if \fIdp netdev\fR...
diff --git a/utilities/ovs-dpctl.c b/utilities/ovs-dpctl.c
index fe44f27..0c12091 100644
--- a/utilities/ovs-dpctl.c
+++ b/utilities/ovs-dpctl.c
@@ -37,6 +37,7 @@
#include "dynamic-string.h"
#include "netdev.h"
#include "odp-util.h"
+#include "shash.h"
#include "svec.h"
#include "timeval.h"
#include "util.h"
@@ -239,8 +240,9 @@ do_add_if(int argc OVS_UNUSED, char *argv[])
run(parsed_dpif_open(argv[1], false, &dpif), "opening datapath");
for (i = 2; i < argc; i++) {
char *save_ptr = NULL;
- char *devname, *suboptions;
- int flags = 0;
+ char *devname, *option;
+ struct shash args;
+ const char *type;
int error;
devname = strtok_r(argv[i], ",", &save_ptr);
@@ -249,31 +251,26 @@ do_add_if(int argc OVS_UNUSED, char *argv[])
continue;
}
- suboptions = strtok_r(NULL, "", &save_ptr);
- if (suboptions) {
- enum {
- AP_INTERNAL
- };
- static char *options[] = {
- "internal"
- };
-
- while (*suboptions != '\0') {
- char *value;
-
- switch (getsubopt(&suboptions, options, &value)) {
- case AP_INTERNAL:
- flags |= ODP_PORT_INTERNAL;
- break;
-
- default:
- ovs_error(0, "unknown suboption '%s'", value);
- break;
- }
+ type = "system";
+ shash_init(&args);
+ while ((option = strtok_r(NULL, "", &save_ptr)) != NULL) {
+ char *save_ptr_2 = NULL;
+ char *key, *value;
+
+ key = strtok_r(option, "=", &save_ptr_2);
+ value = strtok_r(NULL, "", &save_ptr_2);
+ if (!value) {
+ value = "";
+ }
+
+ if (!strcmp(key, "type")) {
+ type = value;
+ } else if (!shash_add_once(&args, key, value)) {
+ ovs_error(0, "duplicate \"%s\" option", key);
}
}
- error = dpif_port_add(dpif, devname, flags, NULL);
+ error = dpif_port_add(dpif, devname, type, &args, NULL);
if (error) {
ovs_error(error, "adding %s to %s failed", devname, argv[1]);
failure = true;
@@ -365,9 +362,11 @@ show_dpif(struct dpif *dpif)
}
query_ports(dpif, &ports, &n_ports);
for (i = 0; i < n_ports; i++) {
- printf("\tport %u: %s", ports[i].port, ports[i].devname);
- if (ports[i].flags & ODP_PORT_INTERNAL) {
- printf(" (internal)");
+ const struct odp_port *p = &ports[i];
+
+ printf("\tport %u: %s", p->port, p->devname);
+ if (strcmp(p->type, "netdev")) {
+ printf(" (%s)", p->type);
}
printf("\n");
}
diff --git a/utilities/ovs-openflowd.c b/utilities/ovs-openflowd.c
index 945b11d..96c5312 100644
--- a/utilities/ovs-openflowd.c
+++ b/utilities/ovs-openflowd.c
@@ -119,7 +119,7 @@ main(int argc, char *argv[])
size_t i;
SVEC_FOR_EACH (i, port, &s.ports) {
- error = dpif_port_add(dpif, port, 0, NULL);
+ error = dpif_port_add(dpif, port, "system", NULL, NULL);
if (error) {
ovs_fatal(error, "failed to add %s as a port", port);
}
diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c
index 6c271fb..c310311 100644
--- a/vswitchd/bridge.c
+++ b/vswitchd/bridge.c
@@ -88,6 +88,7 @@ struct iface {
int dp_ifidx; /* Index within kernel datapath. */
struct netdev *netdev; /* Network device. */
bool enabled; /* May be chosen for flows? */
+ const char *type; /* Usually same as cfg->type. */
const struct ovsrec_interface *cfg;
};
@@ -251,7 +252,6 @@ static void iface_destroy(struct iface *);
static struct iface *iface_lookup(const struct bridge *, const char *name);
static struct iface *iface_from_dp_ifidx(const struct bridge *,
uint16_t dp_ifidx);
-static bool iface_is_internal(const struct bridge *, const char *name);
static void iface_set_mac(struct iface *);
static void iface_update_qos(struct iface *, const struct ovsrec_qos *);
@@ -409,8 +409,7 @@ set_up_iface(const struct ovsrec_interface *iface_cfg, struct iface *iface,
}
} else if (iface->netdev) {
const char *netdev_type = netdev_get_type(iface->netdev);
- const char *iface_type = iface_cfg->type && strlen(iface_cfg->type)
- ? iface_cfg->type : NULL;
+ const char *iface_type = iface_cfg->type[0] ? iface_cfg->type : NULL;
/* An "internal" config type maps to a netdev "system" type. */
if (iface_type && !strcmp(iface_type, "internal")) {
@@ -479,8 +478,7 @@ set_iface_properties(struct bridge *br OVS_UNUSED, struct iface *iface,
/* Set MAC address of internal interfaces other than the local
* interface. */
- if (iface->dp_ifidx != ODPP_LOCAL
- && iface_is_internal(br, iface->name)) {
+ if (iface->dp_ifidx != ODPP_LOCAL && !strcmp(iface->type, "internal")) {
iface_set_mac(iface);
}
@@ -670,14 +668,19 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg)
reconfigure_iface(iface->cfg, iface);
}
} else {
- /* Need to add to datapath. */
- bool internal;
+ /* Add to datapath. */
+ const char *type = iface ? iface->type : "internal";
+ struct shash options;
int error;
- /* Add to datapath. */
- internal = iface_is_internal(br, if_name);
- error = dpif_port_add(br->dpif, if_name,
- internal ? ODP_PORT_INTERNAL : 0, NULL);
+ shash_init(&options);
+ for (i = 0; i < iface->cfg->n_options; i++) {
+ shash_add(&options, iface->cfg->key_options[i],
+ iface->cfg->value_options[i]);
+ }
+ error = dpif_port_add(br->dpif, if_name, type, &options, NULL);
+ shash_destroy(&options);
+
if (error == EFBIG) {
VLOG_ERR("ran out of valid port numbers on %s",
dpif_name(br->dpif));
@@ -3405,8 +3408,15 @@ port_reconfigure(struct port *port, const struct ovsrec_port *cfg)
}
iface->cfg = if_cfg;
} else {
- iface_create(port, if_cfg);
+ iface = iface_create(port, if_cfg);
}
+
+ /* Determine interface type. The local port always has type
+ * "internal". Other ports take their type from the database and
+ * default to "netdev" if none is specified. */
+ iface->type = (!strcmp(if_cfg->name, port->bridge->name) ? "internal"
+ : if_cfg->type[0] ? if_cfg->type
+ : "system");
}
shash_destroy(&new_ifaces);
@@ -3678,7 +3688,6 @@ iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
struct bridge *br = port->bridge;
struct iface *iface;
char *name = if_cfg->name;
- int error;
iface = xzalloc(sizeof *iface);
iface->port = port;
@@ -3692,20 +3701,6 @@ iface_create(struct port *port, const struct ovsrec_interface *if_cfg)
shash_add_assert(&br->iface_by_name, iface->name, iface);
- /* Attempt to create the network interface in case it doesn't exist yet. */
- if (!iface_is_internal(br, iface->name)) {
- error = set_up_iface(if_cfg, iface, true);
- if (error) {
- VLOG_WARN("could not create iface %s: %s", iface->name,
- strerror(error));
-
- shash_find_and_delete_assert(&br->iface_by_name, iface->name);
- free(iface->name);
- free(iface);
- return NULL;
- }
- }
-
if (port->n_ifaces >= port->allocated_ifaces) {
port->ifaces = x2nrealloc(port->ifaces, &port->allocated_ifaces,
sizeof *port->ifaces);
@@ -3767,38 +3762,6 @@ iface_from_dp_ifidx(const struct bridge *br, uint16_t dp_ifidx)
return port_array_get(&br->ifaces, dp_ifidx);
}
-/* Returns true if 'iface' is the name of an "internal" interface on bridge
- * 'br', that is, an interface that is entirely simulated within the datapath.
- * The local port (ODPP_LOCAL) is always an internal interface. Other local
- * interfaces are created by setting "iface.<iface>.internal = true".
- *
- * In addition, we have a kluge-y feature that creates an internal port with
- * the name of a bonded port if "bonding.<bondname>.fake-iface = true" is set.
- * This feature needs to go away in the long term. Until then, this is one
- * reason why this function takes a name instead of a struct iface: the fake
- * interfaces created this way do not have a struct iface. */
-static bool
-iface_is_internal(const struct bridge *br, const char *if_name)
-{
- struct iface *iface;
- struct port *port;
-
- if (!strcmp(if_name, br->name)) {
- return true;
- }
-
- iface = iface_lookup(br, if_name);
- if (iface && !strcmp(iface->cfg->type, "internal")) {
- return true;
- }
-
- port = port_lookup(br, if_name);
- if (port && port->n_ifaces > 1 && port->cfg->bond_fake_iface) {
- return true;
- }
- return false;
-}
-
/* Set Ethernet address of 'iface', if one is specified in the configuration
* file. */
static void
--
1.7.1
More information about the dev
mailing list