Merge changes from citrix branch into master.
authorBen Pfaff <blp@nicira.com>
Mon, 15 Jun 2009 23:04:54 +0000 (16:04 -0700)
committerBen Pfaff <blp@nicira.com>
Mon, 15 Jun 2009 23:04:54 +0000 (16:04 -0700)
26 files changed:
datapath/brc_sysfs.h
datapath/brc_sysfs_dp.c
datapath/brc_sysfs_if.c
datapath/brcompat.c
datapath/datapath.c
datapath/datapath.h
datapath/linux-2.6/Modules.mk
datapath/linux-2.6/compat-2.6/include/linux/kobject.h [new file with mode: 0644]
datapath/linux-2.6/compat-2.6/include/linux/netdevice.h
lib/socket-util.c
lib/socket-util.h
lib/vconn-ssl.c
lib/vconn-stream.c
lib/vconn-tcp.c
lib/vconn-unix.c
lib/vconn.c
secchan/discovery.c
secchan/main.c
secchan/secchan.8.in
tests/automake.mk
tests/test-vconn.c [new file with mode: 0644]
utilities/ovs-controller.8.in
utilities/ovs-discover.8.in
utilities/ovs-discover.c
vswitchd/ovs-vswitchd.conf.5.in
xenserver/vswitch-xen.spec

index 526f5fa..78540d5 100644 (file)
@@ -20,14 +20,5 @@ int brc_sysfs_del_dp(struct datapath *dp);
 int brc_sysfs_add_if(struct net_bridge_port *p);
 int brc_sysfs_del_if(struct net_bridge_port *p);
 
-#include <linux/version.h>
-#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18)
-#define SUPPORT_SYSFS 1
-#else
-/* We only support sysfs on Linux 2.6.18 because that's the only place we
- * really need it (on Xen, for brcompat) and it's a big pain to try to support
- * multiple versions. */
-#endif
-
 #endif /* brc_sysfs.h */
 
index bb779b6..c1e82eb 100644 (file)
 #include "datapath.h"
 #include "dp_dev.h"
 
-#ifdef SUPPORT_SYSFS
+#ifdef CONFIG_SYSFS
 #define to_dev(obj)    container_of(obj, struct device, kobj)
 
 /* Hack to attempt to build on more platforms. */
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
-#define to_kobj(d) &(d)->class_dev.kobj
 #define BRC_DEVICE_ATTR CLASS_DEVICE_ATTR
+#define DEVICE_PARAMS struct class_device *d
+#define DEVICE_ARGS d
+#define DEV_ATTR(NAME) class_device_attr_##NAME
 #else
-#define to_kobj(d) &(d)->dev.kobj
 #define BRC_DEVICE_ATTR DEVICE_ATTR
+#define DEVICE_PARAMS struct device *d, struct device_attribute *attr
+#define DEVICE_ARGS d, attr
+#define DEV_ATTR(NAME) dev_attr_##NAME
 #endif
 
 /*
  * Common code for storing bridge parameters.
  */
-static ssize_t store_bridge_parm(struct class_device *d,
+static ssize_t store_bridge_parm(DEVICE_PARAMS,
                                 const char *buf, size_t len,
                                 void (*set)(struct datapath *, unsigned long))
 {
@@ -76,8 +80,7 @@ static ssize_t store_bridge_parm(struct class_device *d,
 }
 
 
-static ssize_t show_forward_delay(struct class_device *d,
-                                 char *buf)
+static ssize_t show_forward_delay(DEVICE_PARAMS, char *buf)
 {
 #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -99,15 +102,15 @@ static void set_forward_delay(struct datapath *dp, unsigned long val)
 #endif
 }
 
-static ssize_t store_forward_delay(struct class_device *d,
+static ssize_t store_forward_delay(DEVICE_PARAMS,
                                   const char *buf, size_t len)
 {
-       return store_bridge_parm(d, buf, len, set_forward_delay);
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_forward_delay);
 }
 static BRC_DEVICE_ATTR(forward_delay, S_IRUGO | S_IWUSR,
                   show_forward_delay, store_forward_delay);
 
-static ssize_t show_hello_time(struct class_device *d, char *buf)
+static ssize_t show_hello_time(DEVICE_PARAMS, char *buf)
 {
 #if 0
        return sprintf(buf, "%lu\n",
@@ -129,17 +132,16 @@ static void set_hello_time(struct datapath *dp, unsigned long val)
 #endif
 }
 
-static ssize_t store_hello_time(struct class_device *d,
+static ssize_t store_hello_time(DEVICE_PARAMS,
                                const char *buf,
                                size_t len)
 {
-       return store_bridge_parm(d, buf, len, set_hello_time);
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_hello_time);
 }
 static BRC_DEVICE_ATTR(hello_time, S_IRUGO | S_IWUSR, show_hello_time,
                   store_hello_time);
 
-static ssize_t show_max_age(struct class_device *d, 
-                           char *buf)
+static ssize_t show_max_age(DEVICE_PARAMS, char *buf)
 {
 #if 0
        return sprintf(buf, "%lu\n",
@@ -161,15 +163,14 @@ static void set_max_age(struct datapath *dp, unsigned long val)
 #endif
 }
 
-static ssize_t store_max_age(struct class_device *d, 
+static ssize_t store_max_age(DEVICE_PARAMS,
                             const char *buf, size_t len)
 {
-       return store_bridge_parm(d, buf, len, set_max_age);
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_max_age);
 }
 static BRC_DEVICE_ATTR(max_age, S_IRUGO | S_IWUSR, show_max_age, store_max_age);
 
-static ssize_t show_ageing_time(struct class_device *d,
-                               char *buf)
+static ssize_t show_ageing_time(DEVICE_PARAMS, char *buf)
 {
 #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -188,16 +189,15 @@ static void set_ageing_time(struct datapath *dp, unsigned long val)
 #endif
 }
 
-static ssize_t store_ageing_time(struct class_device *d,
+static ssize_t store_ageing_time(DEVICE_PARAMS,
                                 const char *buf, size_t len)
 {
-       return store_bridge_parm(d, buf, len, set_ageing_time);
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_ageing_time);
 }
 static BRC_DEVICE_ATTR(ageing_time, S_IRUGO | S_IWUSR, show_ageing_time,
                   store_ageing_time);
 
-static ssize_t show_stp_state(struct class_device *d,
-                             char *buf)
+static ssize_t show_stp_state(DEVICE_PARAMS, char *buf)
 {
 #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -208,7 +208,7 @@ static ssize_t show_stp_state(struct class_device *d,
 }
 
 
-static ssize_t store_stp_state(struct class_device *d,
+static ssize_t store_stp_state(DEVICE_PARAMS,
                               const char *buf,
                               size_t len)
 {
@@ -236,8 +236,7 @@ static ssize_t store_stp_state(struct class_device *d,
 static BRC_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
                   store_stp_state);
 
-static ssize_t show_priority(struct class_device *d, 
-                            char *buf)
+static ssize_t show_priority(DEVICE_PARAMS, char *buf)
 {
 #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -257,15 +256,14 @@ static void set_priority(struct datapath *dp, unsigned long val)
 #endif
 }
 
-static ssize_t store_priority(struct class_device *d, 
+static ssize_t store_priority(DEVICE_PARAMS,
                               const char *buf, size_t len)
 {
-       return store_bridge_parm(d, buf, len, set_priority);
+       return store_bridge_parm(DEVICE_ARGS, buf, len, set_priority);
 }
 static BRC_DEVICE_ATTR(priority, S_IRUGO | S_IWUSR, show_priority, store_priority);
 
-static ssize_t show_root_id(struct class_device *d, 
-                           char *buf)
+static ssize_t show_root_id(DEVICE_PARAMS, char *buf)
 {
 #if 0
        return br_show_bridge_id(buf, &to_bridge(d)->designated_root);
@@ -275,8 +273,7 @@ static ssize_t show_root_id(struct class_device *d,
 }
 static BRC_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
 
-static ssize_t show_bridge_id(struct class_device *d, 
-                             char *buf)
+static ssize_t show_bridge_id(DEVICE_PARAMS, char *buf)
 {
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
        const unsigned char *addr = dp->ports[ODPP_LOCAL]->dev->dev_addr;
@@ -287,8 +284,7 @@ static ssize_t show_bridge_id(struct class_device *d,
 }
 static BRC_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
 
-static ssize_t show_root_port(struct class_device *d, 
-                             char *buf)
+static ssize_t show_root_port(DEVICE_PARAMS, char *buf)
 {
 #if 0
        return sprintf(buf, "%d\n", to_bridge(d)->root_port);
@@ -298,8 +294,7 @@ static ssize_t show_root_port(struct class_device *d,
 }
 static BRC_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
 
-static ssize_t show_root_path_cost(struct class_device *d,
-                                  char *buf)
+static ssize_t show_root_path_cost(DEVICE_PARAMS, char *buf)
 {
 #if 0
        return sprintf(buf, "%d\n", to_bridge(d)->root_path_cost);
@@ -309,8 +304,7 @@ static ssize_t show_root_path_cost(struct class_device *d,
 }
 static BRC_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
 
-static ssize_t show_topology_change(struct class_device *d,
-                                   char *buf)
+static ssize_t show_topology_change(DEVICE_PARAMS, char *buf)
 {
 #if 0
        return sprintf(buf, "%d\n", to_bridge(d)->topology_change);
@@ -320,8 +314,7 @@ static ssize_t show_topology_change(struct class_device *d,
 }
 static BRC_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
 
-static ssize_t show_topology_change_detected(struct class_device *d,
-                                            char *buf)
+static ssize_t show_topology_change_detected(DEVICE_PARAMS, char *buf)
 {
 #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -333,8 +326,7 @@ static ssize_t show_topology_change_detected(struct class_device *d,
 static BRC_DEVICE_ATTR(topology_change_detected, S_IRUGO,
                   show_topology_change_detected, NULL);
 
-static ssize_t show_hello_timer(struct class_device *d,
-                               char *buf)
+static ssize_t show_hello_timer(DEVICE_PARAMS, char *buf)
 {
 #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -345,8 +337,7 @@ static ssize_t show_hello_timer(struct class_device *d,
 }
 static BRC_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
 
-static ssize_t show_tcn_timer(struct class_device *d, 
-                             char *buf)
+static ssize_t show_tcn_timer(DEVICE_PARAMS, char *buf)
 {
 #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -357,8 +348,7 @@ static ssize_t show_tcn_timer(struct class_device *d,
 }
 static BRC_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
 
-static ssize_t show_topology_change_timer(struct class_device *d,
-                                         char *buf)
+static ssize_t show_topology_change_timer(DEVICE_PARAMS, char *buf)
 {
 #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -370,8 +360,7 @@ static ssize_t show_topology_change_timer(struct class_device *d,
 static BRC_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
                   NULL);
 
-static ssize_t show_gc_timer(struct class_device *d, 
-                            char *buf)
+static ssize_t show_gc_timer(DEVICE_PARAMS, char *buf)
 {
 #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -382,8 +371,7 @@ static ssize_t show_gc_timer(struct class_device *d,
 }
 static BRC_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
 
-static ssize_t show_group_addr(struct class_device *d,
-                              char *buf)
+static ssize_t show_group_addr(DEVICE_PARAMS, char *buf)
 {
 #if 0
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -396,7 +384,7 @@ static ssize_t show_group_addr(struct class_device *d,
 #endif
 }
 
-static ssize_t store_group_addr(struct class_device *d,
+static ssize_t store_group_addr(DEVICE_PARAMS,
                                const char *buf, size_t len)
 {
        struct datapath *dp = dp_dev_get_dp(to_net_dev(d));
@@ -439,23 +427,23 @@ static BRC_DEVICE_ATTR(group_addr, S_IRUGO | S_IWUSR,
                   show_group_addr, store_group_addr);
 
 static struct attribute *bridge_attrs[] = {
-       &class_device_attr_forward_delay.attr,
-       &class_device_attr_hello_time.attr,
-       &class_device_attr_max_age.attr,
-       &class_device_attr_ageing_time.attr,
-       &class_device_attr_stp_state.attr,
-       &class_device_attr_priority.attr,
-       &class_device_attr_bridge_id.attr,
-       &class_device_attr_root_id.attr,
-       &class_device_attr_root_path_cost.attr,
-       &class_device_attr_root_port.attr,
-       &class_device_attr_topology_change.attr,
-       &class_device_attr_topology_change_detected.attr,
-       &class_device_attr_hello_timer.attr,
-       &class_device_attr_tcn_timer.attr,
-       &class_device_attr_topology_change_timer.attr,
-       &class_device_attr_gc_timer.attr,
-       &class_device_attr_group_addr.attr,
+       &DEV_ATTR(forward_delay).attr,
+       &DEV_ATTR(hello_time).attr,
+       &DEV_ATTR(max_age).attr,
+       &DEV_ATTR(ageing_time).attr,
+       &DEV_ATTR(stp_state).attr,
+       &DEV_ATTR(priority).attr,
+       &DEV_ATTR(bridge_id).attr,
+       &DEV_ATTR(root_id).attr,
+       &DEV_ATTR(root_path_cost).attr,
+       &DEV_ATTR(root_port).attr,
+       &DEV_ATTR(topology_change).attr,
+       &DEV_ATTR(topology_change_detected).attr,
+       &DEV_ATTR(hello_timer).attr,
+       &DEV_ATTR(tcn_timer).attr,
+       &DEV_ATTR(topology_change_timer).attr,
+       &DEV_ATTR(gc_timer).attr,
+       &DEV_ATTR(group_addr).attr,
        NULL
 };
 
@@ -476,7 +464,7 @@ static struct attribute_group bridge_group = {
  */
 int brc_sysfs_add_dp(struct datapath *dp)
 {
-       struct kobject *kobj = to_kobj(dp->ports[ODPP_LOCAL]->dev);
+       struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
        int err;
 
        err = sysfs_create_group(kobj, &bridge_group);
@@ -495,12 +483,12 @@ int brc_sysfs_add_dp(struct datapath *dp)
        err = kobject_register(&dp->ifobj);
        if (err) {
                pr_info("%s: can't add kobject (directory) %s/%s\n",
-                               __FUNCTION__, dp_name(dp), dp->ifobj.name);
+                       __FUNCTION__, dp_name(dp), kobject_name(&dp->ifobj));
                goto out2;
        }
 #else
-       br->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, kobj);
-       if (!br->ifobj) {
+       dp->ifobj = kobject_create_and_add(SYSFS_BRIDGE_PORT_SUBDIR, kobj);
+       if (!dp->ifobj) {
                pr_info("%s: can't add kobject (directory) %s/%s\n",
                        __func__, dp_name(dp), SYSFS_BRIDGE_PORT_SUBDIR);
                goto out2;
@@ -516,7 +504,7 @@ int brc_sysfs_add_dp(struct datapath *dp)
 
 int brc_sysfs_del_dp(struct datapath *dp)
 {
-       struct kobject *kobj = to_kobj(dp->ports[ODPP_LOCAL]->dev);
+       struct kobject *kobj = &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj;
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
        kobject_unregister(&dp->ifobj);
@@ -527,7 +515,7 @@ int brc_sysfs_del_dp(struct datapath *dp)
 
        return 0;
 }
-#else /* !SUPPORT_SYSFS */
+#else /* !CONFIG_SYSFS */
 int brc_sysfs_add_dp(struct datapath *dp) { return 0; }
 int brc_sysfs_del_dp(struct datapath *dp) { return 0; }
 int brc_sysfs_add_if(struct net_bridge_port *p) { return 0; }
@@ -537,4 +525,4 @@ int brc_sysfs_del_if(struct net_bridge_port *p)
        kfree(p);
        return 0;
 }
-#endif /* !SUPPORT_SYSFS */
+#endif /* !CONFIG_SYSFS */
index ceda129..7a9b8b8 100644 (file)
@@ -21,7 +21,7 @@
 #include "brc_sysfs.h"
 #include "datapath.h"
 
-#ifdef SUPPORT_SYSFS
+#ifdef CONFIG_SYSFS
 
 struct brport_attribute {
        struct attribute        attr;
@@ -289,18 +289,14 @@ int brc_sysfs_add_if(struct net_bridge_port *p)
        struct brport_attribute **a;
        int err;
 
-       kobject_init(&p->kobj);
-       kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR);
-       p->kobj.ktype = &brport_ktype;
-       p->kobj.kset = NULL;
-       p->kobj.parent = &(p->dev->class_dev.kobj);
-
-       err = kobject_add(&p->kobj);
+       err = kobject_init_and_add(&p->kobj, &brport_ktype,
+                                  &(p->dev->NETDEV_DEV_MEMBER.kobj),
+                                  SYSFS_BRIDGE_PORT_ATTR);
        if (err)
-               goto err_put;
+               goto err;
 
        err = sysfs_create_link(&p->kobj,
-                               &dp->ports[ODPP_LOCAL]->dev->class_dev.kobj,
+                               &dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj,
                                SYSFS_BRIDGE_PORT_LINK);
        if (err)
                goto err_del;
@@ -311,7 +307,11 @@ int brc_sysfs_add_if(struct net_bridge_port *p)
                        goto err_del;
        }
 
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
        err = sysfs_create_link(&dp->ifobj, &p->kobj, p->dev->name);
+#else
+       err = sysfs_create_link(dp->ifobj, &p->kobj, p->dev->name);
+#endif
        if (err)
                goto err_del;
 
@@ -321,8 +321,8 @@ int brc_sysfs_add_if(struct net_bridge_port *p)
 
 err_del:
        kobject_del(&p->kobj);
-err_put:
        kobject_put(&p->kobj);
+err:
        return err;
 }
 
@@ -339,4 +339,4 @@ int brc_sysfs_del_if(struct net_bridge_port *p)
 
        return 0;
 }
-#endif /* SUPPORT_SYSFS */
+#endif /* CONFIG_SYSFS */
index 47805bc..42479e8 100644 (file)
@@ -412,18 +412,14 @@ int brc_add_dp(struct datapath *dp)
 {
        if (!try_module_get(THIS_MODULE))
                return -ENODEV;
-#ifdef SUPPORT_SYSFS
        brc_sysfs_add_dp(dp);
-#endif
 
        return 0;
 }
 
 int brc_del_dp(struct datapath *dp) 
 {
-#ifdef SUPPORT_SYSFS
        brc_sysfs_del_dp(dp);
-#endif
        module_put(THIS_MODULE);
 
        return 0;
@@ -458,10 +454,8 @@ __init brc_init(void)
        dp_del_dp_hook = brc_del_dp;
 
        /* Register hooks for interface adds and deletes */
-#ifdef SUPPORT_SYSFS
        dp_add_if_hook = brc_sysfs_add_if;
        dp_del_if_hook = brc_sysfs_del_if;
-#endif
 
        /* Randomize the initial sequence number.  This is not a security
         * feature; it only helps avoid crossed wires between userspace and
index fc73cac..64e06ce 100644 (file)
@@ -424,10 +424,13 @@ int dp_del_port(struct net_bridge_port *p, struct list_head *dp_devs)
 {
        ASSERT_RTNL();
 
-#ifdef SUPPORT_SYSFS
-       if (p->port_no != ODPP_LOCAL && dp_del_if_hook)
+       if (p->port_no != ODPP_LOCAL && dp_del_if_hook) {
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
                sysfs_remove_link(&p->dp->ifobj, p->dev->name);
+#else
+               sysfs_remove_link(p->dp->ifobj, p->dev->name);
 #endif
+       }
        dp_ifinfo_notify(RTM_DELLINK, p);
 
        p->dp->n_ports--;
@@ -577,6 +580,7 @@ static int dp_frame_hook(struct net_bridge_port *p, struct sk_buff **pskb)
 #endif
 
 #ifdef CONFIG_XEN
+#if LINUX_VERSION_CODE == KERNEL_VERSION(2,6,18)
 /* This code is copied verbatim from net/dev/core.c in Xen's
  * linux-2.6.18-92.1.10.el5.xs5.0.0.394.644.  We can't call those functions
  * directly because they aren't exported. */
@@ -623,7 +627,8 @@ int skb_checksum_setup(struct sk_buff *skb)
 out:
        return -EPROTO;
 }
-#endif
+#endif /* linux == 2.6.18 */
+#endif /* CONFIG_XEN */
 
 int
 dp_output_control(struct datapath *dp, struct sk_buff *skb, int queue_no,
index db24349..3706219 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/netdevice.h>
 #include <linux/workqueue.h>
 #include <linux/skbuff.h>
+#include <linux/version.h>
 #include "flow.h"
 #include "brc_sysfs.h"
 
@@ -66,8 +67,12 @@ struct datapath {
        struct mutex mutex;
        int dp_idx;
 
-#ifdef SUPPORT_SYSFS
+#ifdef CONFIG_SYSFS
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
        struct kobject ifobj;
+#else
+       struct kobject *ifobj;
+#endif
 #endif
 
        int drop_frags;
@@ -96,7 +101,7 @@ struct net_bridge_port {
        u16 port_no;
        struct datapath *dp;
        struct net_device *dev;
-#ifdef SUPPORT_SYSFS
+#ifdef CONFIG_SYSFS
        struct kobject kobj;
 #endif
        struct list_head node;   /* Element in datapath.ports. */
index bbc4c72..e7359a4 100644 (file)
@@ -12,6 +12,7 @@ openvswitch_headers += \
        linux-2.6/compat-2.6/include/linux/ipv6.h \
        linux-2.6/compat-2.6/include/linux/jiffies.h \
        linux-2.6/compat-2.6/include/linux/kernel.h \
+       linux-2.6/compat-2.6/include/linux/kobject.h \
        linux-2.6/compat-2.6/include/linux/log2.h \
        linux-2.6/compat-2.6/include/linux/lockdep.h \
        linux-2.6/compat-2.6/include/linux/mutex.h \
diff --git a/datapath/linux-2.6/compat-2.6/include/linux/kobject.h b/datapath/linux-2.6/compat-2.6/include/linux/kobject.h
new file mode 100644 (file)
index 0000000..7dbb010
--- /dev/null
@@ -0,0 +1,23 @@
+#ifndef __LINUX_KOBJECT_WRAPPER_H
+#define __LINUX_KOBJECT_WRAPPER_H 1
+
+#include_next <linux/kobject.h>
+
+#include <linux/version.h>
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+static inline int kobject_init_and_add(struct kobject *kobj,
+                                       struct kobj_type *ktype,
+                                       struct kobject *parent,
+                                       const char *name)
+{
+       kobject_init(kobj);
+       kobject_set_name(kobj, "%s", name);
+       kobj->ktype = ktype;
+       kobj->kset = NULL;
+       kobj->parent = parent;
+
+       return kobject_add(kobj);
+}
+#endif
+
+#endif /* linux/kobject.h wrapper */
index 32e1735..d291513 100644 (file)
@@ -5,8 +5,19 @@
 
 struct net;
 
+/* Before 2.6.21, struct net_device has a "struct class_device" member named
+ * class_dev.  Beginning with 2.6.21, struct net_device instead has a "struct
+ * device" member named dev.  Otherwise the usage of these members is pretty
+ * much the same. */
+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,21)
+#define NETDEV_DEV_MEMBER class_dev
+#else
+#define NETDEV_DEV_MEMBER dev
+#endif
+
 #ifndef to_net_dev
-#define to_net_dev(class) container_of(class, struct net_device, class_dev)
+#define to_net_dev(class) \
+       container_of(class, struct net_device, NETDEV_DEV_MEMBER)
 #endif
 
 #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
index 33e179e..e5b86e4 100644 (file)
@@ -23,6 +23,7 @@
 #include <poll.h>
 #include <stddef.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <sys/resource.h>
 #include <sys/un.h>
@@ -299,6 +300,172 @@ guess_netmask(uint32_t ip)
             : htonl(0));                          /* ??? */
 }
 
+/* Opens a non-blocking TCP socket and connects to 'target', which should be a
+ * string in the format "<host>[:<port>]", where <host> is required and <port>
+ * is optional, with 'default_port' assumed if <port> is omitted.
+ *
+ * On success, returns 0 (indicating connection complete) or EAGAIN (indicating
+ * connection in progress), in which case the new file descriptor is stored
+ * into '*fdp'.  On failure, returns a positive errno value other than EAGAIN
+ * and stores -1 into '*fdp'.
+ *
+ * If 'sinp' is non-null, then on success the target address is stored into
+ * '*sinp'. */
+int
+tcp_open_active(const char *target_, uint16_t default_port,
+                struct sockaddr_in *sinp, int *fdp)
+{
+    char *target = xstrdup(target_);
+    char *save_ptr = NULL;
+    const char *host_name;
+    const char *port_string;
+    struct sockaddr_in sin;
+    int fd = -1;
+    int error;
+
+    /* Defaults. */
+    memset(&sin, 0, sizeof sin);
+    sin.sin_family = AF_INET;
+    sin.sin_port = htons(default_port);
+
+    /* Tokenize. */
+    host_name = strtok_r(target, ":", &save_ptr);
+    port_string = strtok_r(NULL, ":", &save_ptr);
+    if (!host_name) {
+        ovs_error(0, "%s: bad peer name format", target_);
+        error = EAFNOSUPPORT;
+        goto exit;
+    }
+
+    /* Look up IP, port. */
+    error = lookup_ip(host_name, &sin.sin_addr);
+    if (error) {
+        goto exit;
+    }
+    if (port_string && atoi(port_string)) {
+        sin.sin_port = htons(atoi(port_string));
+    }
+
+    /* Create non-blocking socket. */
+    fd = socket(AF_INET, SOCK_STREAM, 0);
+    if (fd < 0) {
+        VLOG_ERR("%s: socket: %s", target_, strerror(errno));
+        error = errno;
+        goto exit;
+    }
+    error = set_nonblocking(fd);
+    if (error) {
+        goto exit_close;
+    }
+
+    /* Connect. */
+    error = connect(fd, (struct sockaddr *) &sin, sizeof sin) == 0 ? 0 : errno;
+    if (error == EINPROGRESS) {
+        error = EAGAIN;
+    } else if (error && error != EAGAIN) {
+        goto exit_close;
+    }
+
+    /* Success: error is 0 or EAGAIN. */
+    goto exit;
+
+exit_close:
+    close(fd);
+exit:
+    if (!error || error == EAGAIN) {
+        if (sinp) {
+            *sinp = sin;
+        }
+        *fdp = fd;
+    } else {
+        *fdp = -1;
+    }
+    free(target);
+    return error;
+}
+
+/* Opens a non-blocking TCP socket, binds to 'target', and listens for incoming
+ * connections.  'target' should be a string in the format "[<port>][:<ip>]",
+ * where both <port> and <ip> are optional.  If <port> is omitted, it defaults
+ * to 'default_port'; if <ip> is omitted it defaults to the wildcard IP
+ * address.
+ *
+ * The socket will have SO_REUSEADDR turned on.
+ *
+ * On success, returns a non-negative file descriptor.  On failure, returns a
+ * negative errno value. */
+int
+tcp_open_passive(const char *target_, uint16_t default_port)
+{
+    char *target = xstrdup(target_);
+    char *string_ptr = target;
+    struct sockaddr_in sin;
+    const char *host_name;
+    const char *port_string;
+    int fd, error;
+    unsigned int yes  = 1;
+
+    /* Address defaults. */
+    memset(&sin, 0, sizeof sin);
+    sin.sin_family = AF_INET;
+    sin.sin_addr.s_addr = htonl(INADDR_ANY);
+    sin.sin_port = htons(default_port);
+
+    /* Parse optional port number. */
+    port_string = strsep(&string_ptr, ":");
+    if (port_string && atoi(port_string)) {
+        sin.sin_port = htons(atoi(port_string));
+    }
+
+    /* Parse optional bind IP. */
+    host_name = strsep(&string_ptr, ":");
+    if (host_name && host_name[0]) {
+        error = lookup_ip(host_name, &sin.sin_addr);
+        if (error) {
+            goto exit;
+        }
+    }
+
+    /* Create non-blocking socket, set SO_REUSEADDR. */
+    fd = socket(AF_INET, SOCK_STREAM, 0);
+    if (fd < 0) {
+        error = errno;
+        VLOG_ERR("%s: socket: %s", target_, strerror(error));
+        goto exit;
+    }
+    error = set_nonblocking(fd);
+    if (error) {
+        goto exit_close;
+    }
+    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
+        error = errno;
+        VLOG_ERR("%s: setsockopt(SO_REUSEADDR): %s", target_, strerror(error));
+        goto exit_close;
+    }
+
+    /* Bind. */
+    if (bind(fd, (struct sockaddr *) &sin, sizeof sin) < 0) {
+        error = errno;
+        VLOG_ERR("%s: bind: %s", target_, strerror(error));
+        goto exit_close;
+    }
+
+    /* Listen. */
+    if (listen(fd, 10) < 0) {
+        error = errno;
+        VLOG_ERR("%s: listen: %s", target_, strerror(error));
+        goto exit_close;
+    }
+    error = 0;
+    goto exit;
+
+exit_close:
+    close(fd);
+exit:
+    free(target);
+    return error ? -error : fd;
+}
+
 int
 read_fully(int fd, void *p_, size_t size, size_t *bytes_read)
 {
index 34dc92f..d808838 100644 (file)
@@ -33,6 +33,10 @@ int make_unix_socket(int style, bool nonblock, bool passcred,
 int get_unix_name_len(socklen_t sun_len);
 uint32_t guess_netmask(uint32_t ip);
 
+int tcp_open_active(const char *target, uint16_t default_port,
+                    struct sockaddr_in *sinp, int *fdp);
+int tcp_open_passive(const char *target, uint16_t default_port);
+
 int read_fully(int fd, void *, size_t, size_t *bytes_read);
 int write_fully(int fd, const void *, size_t, size_t *bytes_written);
 
index 905996f..1a32903 100644 (file)
@@ -269,58 +269,21 @@ ssl_vconn_cast(struct vconn *vconn)
 static int
 ssl_open(const char *name, char *suffix, struct vconn **vconnp)
 {
-    char *save_ptr, *host_name, *port_string;
     struct sockaddr_in sin;
-    int retval;
-    int fd;
-
-    retval = ssl_init();
-    if (retval) {
-        return retval;
-    }
-
-    host_name = strtok_r(suffix, ":", &save_ptr);
-    port_string = strtok_r(NULL, ":", &save_ptr);
-    if (!host_name) {
-        ovs_error(0, "%s: bad peer name format", name);
-        return EAFNOSUPPORT;
-    }
-
-    memset(&sin, 0, sizeof sin);
-    sin.sin_family = AF_INET;
-    if (lookup_ip(host_name, &sin.sin_addr)) {
-        return ENOENT;
-    }
-    sin.sin_port = htons(port_string && *port_string ? atoi(port_string)
-                         : OFP_SSL_PORT);
+    int error, fd;
 
-    /* Create socket. */
-    fd = socket(AF_INET, SOCK_STREAM, 0);
-    if (fd < 0) {
-        VLOG_ERR("%s: socket: %s", name, strerror(errno));
-        return errno;
-    }
-    retval = set_nonblocking(fd);
-    if (retval) {
-        close(fd);
-        return retval;
+    error = ssl_init();
+    if (error) {
+        return error;
     }
 
-    /* Connect socket. */
-    retval = connect(fd, (struct sockaddr *) &sin, sizeof sin);
-    if (retval < 0) {
-        if (errno == EINPROGRESS) {
-            return new_ssl_vconn(name, fd, CLIENT, STATE_TCP_CONNECTING,
-                                 &sin, vconnp);
-        } else {
-            int error = errno;
-            VLOG_ERR("%s: connect: %s", name, strerror(error));
-            close(fd);
-            return error;
-        }
+    error = tcp_open_active(suffix, OFP_SSL_PORT, &sin, &fd);
+    if (fd >= 0) {
+        int state = error ? STATE_TCP_CONNECTING : STATE_SSL_CONNECTING;
+        return new_ssl_vconn(name, fd, CLIENT, state, &sin, vconnp);
     } else {
-        return new_ssl_vconn(name, fd, CLIENT, STATE_SSL_CONNECTING,
-                             &sin, vconnp);
+        VLOG_ERR("%s: connect: %s", name, strerror(error));
+        return error;
     }
 }
 
@@ -793,55 +756,18 @@ pssl_pvconn_cast(struct pvconn *pvconn)
 static int
 pssl_open(const char *name, char *suffix, struct pvconn **pvconnp)
 {
-    struct sockaddr_in sin;
     struct pssl_pvconn *pssl;
     int retval;
     int fd;
-    unsigned int yes = 1;
 
     retval = ssl_init();
     if (retval) {
         return retval;
     }
 
-    /* Create socket. */
-    fd = socket(AF_INET, SOCK_STREAM, 0);
+    fd = tcp_open_passive(suffix, OFP_SSL_PORT);
     if (fd < 0) {
-        int error = errno;
-        VLOG_ERR("%s: socket: %s", name, strerror(error));
-        return error;
-    }
-
-    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
-        int error = errno;
-        VLOG_ERR("%s: setsockopt(SO_REUSEADDR): %s", name, strerror(errno));
-        return error;
-    }
-
-    memset(&sin, 0, sizeof sin);
-    sin.sin_family = AF_INET;
-    sin.sin_addr.s_addr = htonl(INADDR_ANY);
-    sin.sin_port = htons(atoi(suffix) ? atoi(suffix) : OFP_SSL_PORT);
-    retval = bind(fd, (struct sockaddr *) &sin, sizeof sin);
-    if (retval < 0) {
-        int error = errno;
-        VLOG_ERR("%s: bind: %s", name, strerror(error));
-        close(fd);
-        return error;
-    }
-
-    retval = listen(fd, 10);
-    if (retval < 0) {
-        int error = errno;
-        VLOG_ERR("%s: listen: %s", name, strerror(error));
-        close(fd);
-        return error;
-    }
-
-    retval = set_nonblocking(fd);
-    if (retval) {
-        close(fd);
-        return retval;
+        return -fd;
     }
 
     pssl = xmalloc(sizeof *pssl);
index a9fcd98..f5a8602 100644 (file)
@@ -270,23 +270,7 @@ new_pstream_pvconn(const char *name, int fd,
                                    size_t sa_len, struct vconn **),
                   struct pvconn **pvconnp)
 {
-    struct pstream_pvconn *ps;
-    int retval;
-
-    retval = set_nonblocking(fd);
-    if (retval) {
-        close(fd);
-        return retval;
-    }
-
-    if (listen(fd, 10) < 0) {
-        int error = errno;
-        VLOG_ERR("%s: listen: %s", name, strerror(error));
-        close(fd);
-        return error;
-    }
-
-    ps = xmalloc(sizeof *ps);
+    struct pstream_pvconn *ps = xmalloc(sizeof *ps);
     pvconn_init(&ps->pvconn, &pstream_pvconn_class, name);
     ps->fd = fd;
     ps->accept_cb = accept_cb;
index 911fe6d..9451322 100644 (file)
@@ -57,51 +57,15 @@ new_tcp_vconn(const char *name, int fd, int connect_status,
 static int
 tcp_open(const char *name, char *suffix, struct vconn **vconnp)
 {
-    char *save_ptr;
-    const char *host_name;
-    const char *port_string;
     struct sockaddr_in sin;
-    int retval;
-    int fd;
-
-    host_name = strtok_r(suffix, ":", &save_ptr);
-    port_string = strtok_r(NULL, ":", &save_ptr);
-    if (!host_name) {
-        ovs_error(0, "%s: bad peer name format", name);
-        return EAFNOSUPPORT;
-    }
-
-    memset(&sin, 0, sizeof sin);
-    sin.sin_family = AF_INET;
-    if (lookup_ip(host_name, &sin.sin_addr)) {
-        return ENOENT;
-    }
-    sin.sin_port = htons(port_string ? atoi(port_string) : OFP_TCP_PORT);
-
-    fd = socket(AF_INET, SOCK_STREAM, 0);
-    if (fd < 0) {
-        VLOG_ERR("%s: socket: %s", name, strerror(errno));
-        return errno;
-    }
-
-    retval = set_nonblocking(fd);
-    if (retval) {
-        close(fd);
-        return retval;
-    }
+    int fd, error;
 
-    retval = connect(fd, (struct sockaddr *) &sin, sizeof sin);
-    if (retval < 0) {
-        if (errno == EINPROGRESS) {
-            return new_tcp_vconn(name, fd, EAGAIN, &sin, vconnp);
-        } else {
-            int error = errno;
-            VLOG_ERR("%s: connect: %s", name, strerror(error));
-            close(fd);
-            return error;
-        }
+    error = tcp_open_active(suffix, OFP_TCP_PORT, NULL, &fd);
+    if (fd >= 0) {
+        return new_tcp_vconn(name, fd, error, &sin, vconnp);
     } else {
-        return new_tcp_vconn(name, fd, 0, &sin, vconnp);
+        VLOG_ERR("%s: connect: %s", name, strerror(error));
+        return error;
     }
 }
 
@@ -121,37 +85,16 @@ static int ptcp_accept(int fd, const struct sockaddr *sa, size_t sa_len,
                        struct vconn **vconnp);
 
 static int
-ptcp_open(const char *name, char *suffix, struct pvconn **pvconnp)
+ptcp_open(const char *name UNUSED, char *suffix, struct pvconn **pvconnp)
 {
-    struct sockaddr_in sin;
-    int retval;
     int fd;
-    unsigned int yes  = 1;
 
-    fd = socket(AF_INET, SOCK_STREAM, 0);
+    fd = tcp_open_passive(suffix, OFP_TCP_PORT);
     if (fd < 0) {
-        VLOG_ERR("%s: socket: %s", name, strerror(errno));
-        return errno;
-    }
-
-    if (setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &yes, sizeof yes) < 0) {
-        VLOG_ERR("%s: setsockopt(SO_REUSEADDR): %s", name, strerror(errno));
-        return errno;
-    }
-
-    memset(&sin, 0, sizeof sin);
-    sin.sin_family = AF_INET;
-    sin.sin_addr.s_addr = htonl(INADDR_ANY);
-    sin.sin_port = htons(atoi(suffix) ? atoi(suffix) : OFP_TCP_PORT);
-    retval = bind(fd, (struct sockaddr *) &sin, sizeof sin);
-    if (retval < 0) {
-        int error = errno;
-        VLOG_ERR("%s: bind: %s", name, strerror(error));
-        close(fd);
-        return error;
+        return -fd;
+    } else {
+        return new_pstream_pvconn("ptcp", fd, ptcp_accept, pvconnp);
     }
-
-    return new_pstream_pvconn("ptcp", fd, ptcp_accept, pvconnp);
 }
 
 static int
index aec2e31..baa9861 100644 (file)
@@ -81,7 +81,7 @@ static int punix_accept(int fd, const struct sockaddr *sa, size_t sa_len,
 static int
 punix_open(const char *name UNUSED, char *suffix, struct pvconn **pvconnp)
 {
-    int fd;
+    int fd, error;
 
     fd = make_unix_socket(SOCK_STREAM, true, true, suffix, NULL);
     if (fd < 0) {
@@ -89,6 +89,19 @@ punix_open(const char *name UNUSED, char *suffix, struct pvconn **pvconnp)
         return errno;
     }
 
+    error = set_nonblocking(fd);
+    if (error) {
+        close(fd);
+        return error;
+    }
+
+    if (listen(fd, 10) < 0) {
+        error = errno;
+        VLOG_ERR("%s: listen: %s", name, strerror(error));
+        close(fd);
+        return error;
+    }
+
     return new_pstream_pvconn("punix", fd, punix_accept, pvconnp);
 }
 
index a006efb..1999d74 100644 (file)
@@ -139,12 +139,12 @@ vconn_usage(bool active, bool passive, bool bootstrap UNUSED)
 
     if (passive) {
         printf("Passive OpenFlow connection methods:\n");
-        printf("  ptcp:[PORT]             "
-               "listen to TCP PORT (default: %d)\n",
+        printf("  ptcp:[PORT][:IP]        "
+               "listen to TCP PORT (default: %d) on IP\n",
                OFP_TCP_PORT);
 #ifdef HAVE_OPENSSL
-        printf("  pssl:[PORT]             "
-               "listen for SSL on PORT (default: %d)\n",
+        printf("  pssl:[PORT][:IP]        "
+               "listen for SSL on PORT (default: %d) on IP\n",
                OFP_SSL_PORT);
 #endif
         printf("  punix:FILE              "
@@ -339,7 +339,7 @@ vcs_recv_hello(struct vconn *vconn)
 
     if (retval != EAGAIN) {
         vconn->state = VCS_DISCONNECTED;
-        vconn->error = retval;
+        vconn->error = retval == EOF ? ECONNRESET : retval;
     }
 }
 
@@ -433,10 +433,7 @@ vconn_recv(struct vconn *vconn, struct ofpbuf **msgp)
 static int
 do_recv(struct vconn *vconn, struct ofpbuf **msgp)
 {
-    int retval;
-
-again:
-    retval = (vconn->class->recv)(vconn, msgp);
+    int retval = (vconn->class->recv)(vconn, msgp);
     if (!retval) {
         struct ofp_header *oh;
 
@@ -456,20 +453,6 @@ again:
             && oh->type != OFPT_VENDOR)
         {
             if (vconn->version < 0) {
-                if (oh->type == OFPT_PACKET_IN
-                    || oh->type == OFPT_FLOW_EXPIRED
-                    || oh->type == OFPT_PORT_STATUS) {
-                    /* The kernel datapath is stateless and doesn't really
-                     * support version negotiation, so it can end up sending
-                     * these asynchronous message before version negotiation
-                     * is complete.  Just ignore them.
-                     *
-                     * (After we move OFPT_PORT_STATUS messages from the kernel
-                     * into secchan, we won't get those here, since secchan
-                     * does proper version negotiation.) */
-                    ofpbuf_delete(*msgp);
-                    goto again;
-                }
                 VLOG_ERR_RL(&bad_ofmsg_rl,
                             "%s: received OpenFlow message type %"PRIu8" "
                             "before version negotiation complete",
index da52482..0c08de3 100644 (file)
@@ -168,7 +168,7 @@ discovery_set_accept_controller_re(struct discovery *d, const char *re_)
     int error;
     char *re;
 
-    re = (!re_ ? xstrdup(vconn_ssl_is_configured() ? "^ssl:.*" : ".*")
+    re = (!re_ ? xstrdup(vconn_ssl_is_configured() ? "^ssl:.*" : "^tcp:.*")
           : re_[0] == '^' ? xstrdup(re_) : xasprintf("^%s", re_));
     regex = xmalloc(sizeof *regex);
     error = regcomp(regex, re, REG_NOSUB | REG_EXTENDED);
index b3192ab..d1037a8 100644 (file)
@@ -497,7 +497,8 @@ parse_options(int argc, char *argv[], struct ofsettings *s)
 
     /* Set accept_controller_regex. */
     if (!s->accept_controller_re) {
-        s->accept_controller_re = vconn_ssl_is_configured() ? "^ssl:.*" : ".*";
+        s->accept_controller_re
+            = vconn_ssl_is_configured() ? "^ssl:.*" : "^tcp:.*";
     }
 
     /* Mode of operation. */
index b40842a..3b781ae 100644 (file)
@@ -182,8 +182,8 @@ names match the regular expression will be accepted.
 The default regular expression is \fBssl:.*\fR (meaning that only SSL
 controller connections will be accepted) when any of the SSL
 configuration options \fB--private-key\fR, \fB--certificate\fR, or
-\fB--ca-cert\fR is specified.  The default is \fB.*\fR otherwise
-(meaning that any controller will be accepted).
+\fB--ca-cert\fR is specified.  The default is \fB^tcp:.*\fR otherwise
+(meaning that only TCP controller connections will be accepted).
 
 The \fIregex\fR is implicitly anchored at the beginning of the
 controller location string, as if it begins with \fB^\fR.
@@ -307,14 +307,20 @@ multiple connection methods.
 
 .RS
 .TP
-\fBpssl:\fR[\fIport\fR]
+\fBpssl:\fR[\fIport\fR][\fB:\fIip\fR]
 Listens for SSL connections on \fIport\fR (default: 6633).  The
 \fB--private-key\fR, \fB--certificate\fR, and \fB--ca-cert\fR options
 are mandatory when this form is used.
+By default, \fB\*(PN\fR listens for connections to any local IP
+address, but \fIip\fR may be specified to listen only for connections
+to the given \fIip\fR.
 
 .TP
-\fBptcp:\fR[\fIport\fR]
+\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]
 Listens for TCP connections on \fIport\fR (default: 6633).
+By default, \fB\*(PN\fR listens for connections to any local IP
+address, but \fIip\fR may be specified to listen only for connections
+to the given \fIip\fR.
 
 .TP
 \fBpunix:\fIfile\fR
index 3a417c7..e251317 100644 (file)
@@ -64,3 +64,9 @@ stp_files = \
 TESTS_ENVIRONMENT += stp_files='$(stp_files)'
 
 EXTRA_DIST += $(stp_files)
+
+TESTS += tests/test-vconn
+noinst_PROGRAMS += tests/test-vconn
+tests_test_vconn_SOURCES = tests/test-vconn.c
+tests_test_vconn_LDADD = lib/libopenvswitch.a $(SSL_LIBS)
+
diff --git a/tests/test-vconn.c b/tests/test-vconn.c
new file mode 100644 (file)
index 0000000..cefe899
--- /dev/null
@@ -0,0 +1,384 @@
+/*
+ * Copyright (c) 2009 Nicira Networks.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <config.h>
+#include "vconn.h"
+#include <errno.h>
+#include <inttypes.h>
+#include <signal.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include "poll-loop.h"
+#include "socket-util.h"
+#include "timeval.h"
+#include "util.h"
+#include "vlog.h"
+
+#undef NDEBUG
+#include <assert.h>
+
+struct fake_pvconn {
+    const char *type;
+    char *pvconn_name;
+    char *vconn_name;
+    int fd;
+};
+
+static void
+fpv_create(const char *type, struct fake_pvconn *fpv)
+{
+    fpv->type = type;
+    if (!strcmp(type, "unix")) {
+        static int unix_count = 0;
+        char *bind_path;
+        int fd;
+
+        bind_path = xasprintf("fake-pvconn.%d", unix_count++);
+        fd = make_unix_socket(SOCK_STREAM, false, false, bind_path, NULL);
+        if (fd < 0) {
+            ovs_fatal(-fd, "%s: could not bind to Unix domain socket",
+                      bind_path);
+        }
+
+        fpv->pvconn_name = xasprintf("punix:%s", bind_path);
+        fpv->vconn_name = xasprintf("unix:%s", bind_path);
+        fpv->fd = fd;
+        free(bind_path);
+    } else if (!strcmp(type, "tcp")) {
+        struct sockaddr_in sin;
+        socklen_t sin_len;
+        int fd;
+
+        /* Create TCP socket. */
+        fd = socket(PF_INET, SOCK_STREAM, 0);
+        if (fd < 0) {
+            ovs_fatal(errno, "failed to create TCP socket");
+        }
+
+        /* Bind TCP socket to localhost on any available port. */
+        sin.sin_family = AF_INET;
+        sin.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
+        sin.sin_port = htons(0);
+        if (bind(fd, (struct sockaddr *) &sin, sizeof sin) < 0) {
+            ovs_fatal(errno, "failed to bind TCP socket");
+        }
+
+        /* Retrieve socket's port number. */
+        sin_len = sizeof sin;
+        if (getsockname(fd, &sin, &sin_len) < 0) {
+            ovs_fatal(errno, "failed to read TCP socket name");
+        }
+        if (sin_len != sizeof sin || sin.sin_family != AF_INET) {
+            ovs_fatal(errno, "bad TCP socket name");
+        }
+
+        /* Save info. */
+        fpv->pvconn_name = xasprintf("ptcp:%"PRIu16":127.0.0.1",
+                                    ntohs(sin.sin_port));
+        fpv->vconn_name = xasprintf("tcp:127.0.0.1:%"PRIu16,
+                                    ntohs(sin.sin_port));
+        fpv->fd = fd;
+    } else {
+        abort();
+    }
+
+    /* Listen. */
+    if (listen(fpv->fd, 0) < 0) {
+        ovs_fatal(errno, "%s: listen failed", fpv->vconn_name);
+    }
+}
+
+static int
+fpv_accept(struct fake_pvconn *fpv)
+{
+    int fd;
+
+    fd = accept(fpv->fd, NULL, NULL);
+    if (fd < 0) {
+        ovs_fatal(errno, "%s: accept failed", fpv->pvconn_name);
+    }
+    return fd;
+}
+
+static void
+fpv_close(struct fake_pvconn *fpv)
+{
+    if (fpv->fd >= 0) {
+        if (close(fpv->fd) < 0) {
+            ovs_fatal(errno, "failed to close %s fake pvconn", fpv->type);
+        }
+        fpv->fd = -1;
+    }
+}
+
+static void
+fpv_destroy(struct fake_pvconn *fpv)
+{
+    fpv_close(fpv);
+    free(fpv->pvconn_name);
+    free(fpv->vconn_name);
+}
+
+/* Connects to a fake_pvconn with vconn_open(), then closes the listener and
+ * verifies that vconn_connect() reports 'expected_error'. */
+static void
+test_refuse_connection(const char *type, int expected_error)
+{
+    struct fake_pvconn fpv;
+    struct vconn *vconn;
+
+    fpv_create(type, &fpv);
+    assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
+    fpv_close(&fpv);
+    assert(vconn_connect(vconn) == expected_error);
+    vconn_close(vconn);
+    fpv_destroy(&fpv);
+}
+
+/* Connects to a fake_pvconn with vconn_open(), accepts that connection and
+ * closes it immediately, and verifies that vconn_connect() reports
+ * 'expected_error'. */
+static void
+test_accept_then_close(const char *type, int expected_error)
+{
+    struct fake_pvconn fpv;
+    struct vconn *vconn;
+
+    fpv_create(type, &fpv);
+    assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
+    close(fpv_accept(&fpv));
+    fpv_close(&fpv);
+    assert(vconn_connect(vconn) == expected_error);
+    vconn_close(vconn);
+    fpv_destroy(&fpv);
+}
+
+/* Connects to a fake_pvconn with vconn_open(), accepts that connection and
+ * reads the hello message from it, then closes the connection and verifies
+ * that vconn_connect() reports 'expected_error'. */
+static void
+test_read_hello(const char *type, int expected_error)
+{
+    struct fake_pvconn fpv;
+    struct vconn *vconn;
+    int fd;
+
+    fpv_create(type, &fpv);
+    assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
+    fd = fpv_accept(&fpv);
+    fpv_destroy(&fpv);
+    assert(!set_nonblocking(fd));
+    for (;;) {
+       struct ofp_header hello;
+       int retval;
+
+       retval = read(fd, &hello, sizeof hello);
+       if (retval == sizeof hello) {
+           assert(hello.version == OFP_VERSION);
+           assert(hello.type == OFPT_HELLO);
+           assert(hello.length == htons(sizeof hello));
+           break;
+       } else {
+           assert(errno == EAGAIN);
+       }
+
+       assert(vconn_connect(vconn) == EAGAIN);
+       vconn_connect_wait(vconn);
+       poll_fd_wait(fd, POLLIN);
+       poll_block();
+    }
+    close(fd);
+    assert(vconn_connect(vconn) == expected_error);
+    vconn_close(vconn);
+}
+
+/* Connects to a fake_pvconn with vconn_open(), accepts that connection and
+ * sends the 'out' bytes in 'out_size' to it (presumably an OFPT_HELLO
+ * message), then verifies that vconn_connect() reports
+ * 'expect_connect_error'. */
+static void
+test_send_hello(const char *type, const void *out, size_t out_size,
+                int expect_connect_error)
+{
+    struct fake_pvconn fpv;
+    struct vconn *vconn;
+    bool read_hello, connected;
+    struct ofpbuf *msg;
+    int fd;
+
+    fpv_create(type, &fpv);
+    assert(!vconn_open(fpv.vconn_name, OFP_VERSION, &vconn));
+    fd = fpv_accept(&fpv);
+    fpv_destroy(&fpv);
+
+    write(fd, out, out_size);
+
+    assert(!set_nonblocking(fd));
+
+    read_hello = connected = false;
+    for (;;) {
+       if (!read_hello) {
+           struct ofp_header hello;
+           int retval = read(fd, &hello, sizeof hello);
+           if (retval == sizeof hello) {
+               assert(hello.version == OFP_VERSION);
+               assert(hello.type == OFPT_HELLO);
+               assert(hello.length == htons(sizeof hello));
+               read_hello = true;
+           } else {
+               assert(errno == EAGAIN);
+           }
+       }
+
+       if (!connected) {
+           int error = vconn_connect(vconn);
+           if (error == expect_connect_error) {
+               if (!error) {
+                   connected = true;
+               } else {
+                   close(fd);
+                   vconn_close(vconn);
+                   return;
+               }
+           } else {
+               assert(error == EAGAIN);
+           }
+       }
+
+       if (read_hello && connected) {
+           break;
+       }
+
+       if (!connected) {
+           vconn_connect_wait(vconn);
+       }
+       if (!read_hello) {
+           poll_fd_wait(fd, POLLIN);
+       }
+       poll_block();
+    }
+    close(fd);
+    assert(vconn_recv(vconn, &msg) == EOF);
+    vconn_close(vconn);
+}
+
+/* Try connecting and sending a normal hello, which should succeed. */
+static void
+test_send_plain_hello(const char *type)
+{
+    struct ofp_header hello;
+
+    hello.version = OFP_VERSION;
+    hello.type = OFPT_HELLO;
+    hello.length = htons(sizeof hello);
+    hello.xid = htonl(0x12345678);
+    test_send_hello(type, &hello, sizeof hello, 0);
+}
+
+/* Try connecting and sending an extra-long hello, which should succeed (since
+ * the specification says that implementations must accept and ignore extra
+ * data). */
+static void
+test_send_long_hello(const char *type)
+{
+    struct ofp_header hello;
+    char buffer[sizeof hello * 2];
+
+    hello.version = OFP_VERSION;
+    hello.type = OFPT_HELLO;
+    hello.length = htons(sizeof buffer);
+    hello.xid = htonl(0x12345678);
+    memset(buffer, 0, sizeof buffer);
+    memcpy(buffer, &hello, sizeof hello);
+    test_send_hello(type, buffer, sizeof buffer, 0);
+}
+
+/* Try connecting and sending an echo request instead of a hello, which should
+ * fail with EPROTO. */
+static void
+test_send_echo_hello(const char *type)
+{
+    struct ofp_header echo;
+
+    echo.version = OFP_VERSION;
+    echo.type = OFPT_ECHO_REQUEST;
+    echo.length = htons(sizeof echo);
+    echo.xid = htonl(0x89abcdef);
+    test_send_hello(type, &echo, sizeof echo, EPROTO);
+}
+
+/* Try connecting and sending a hello packet that has its length field as 0,
+ * which should fail with EPROTO. */
+static void
+test_send_short_hello(const char *type)
+{
+    struct ofp_header hello;
+
+    memset(&hello, 0, sizeof hello);
+    test_send_hello(type, &hello, sizeof hello, EPROTO);
+}
+
+/* Try connecting and sending a hello packet that has a bad version, which
+ * should fail with EPROTO. */
+static void
+test_send_invalid_version_hello(const char *type)
+{
+    struct ofp_header hello;
+
+    hello.version = OFP_VERSION - 1;
+    hello.type = OFPT_HELLO;
+    hello.length = htons(sizeof hello);
+    hello.xid = htonl(0x12345678);
+    test_send_hello(type, &hello, sizeof hello, EPROTO);
+}
+
+int
+main(int argc UNUSED, char *argv[])
+{
+    set_program_name(argv[0]);
+    time_init();
+    vlog_init();
+    signal(SIGPIPE, SIG_IGN);
+    vlog_set_levels(VLM_ANY_MODULE, VLF_ANY_FACILITY, VLL_EMER);
+
+    time_alarm(10);
+
+    test_refuse_connection("unix", EPIPE);
+    test_refuse_connection("tcp", ECONNRESET);
+
+    test_accept_then_close("unix", EPIPE);
+    test_accept_then_close("tcp", ECONNRESET);
+
+    test_read_hello("unix", ECONNRESET);
+    test_read_hello("tcp", ECONNRESET);
+
+    test_send_plain_hello("unix");
+    test_send_plain_hello("tcp");
+
+    test_send_long_hello("unix");
+    test_send_long_hello("tcp");
+
+    test_send_echo_hello("unix");
+    test_send_echo_hello("tcp");
+
+    test_send_short_hello("unix");
+    test_send_short_hello("tcp");
+
+    test_send_invalid_version_hello("unix");
+    test_send_invalid_version_hello("tcp");
+
+    return 0;
+}
index 31c7a86..380ddec 100644 (file)
@@ -16,16 +16,22 @@ protocol, causing them to function as L2 MAC-learning switches or hub.
 one or more of the following OpenFlow connection methods:
 
 .TP
-\fBpssl:\fR[\fIport\fR]
+\fBpssl:\fR[\fIport\fR][\fB:\fIip\fR]
 Listens for SSL connections from remote OpenFlow switches on
 \fIport\fR (default: 6633).  The \fB--private-key\fR,
 \fB--certificate\fR, and \fB--ca-cert\fR options are mandatory when
 this form is used.
+By default, \fB\*(PN\fR listens for connections to any local IP
+address, but \fIip\fR may be specified to listen only for connections
+to the given \fIip\fR.
 
 .TP
-\fBptcp:\fR[\fIport\fR]
+\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]
 Listens for TCP connections from remote OpenFlow switches on
 \fIport\fR (default: 6633).
+By default, \fB\*(PN\fR listens for connections to any local IP
+address, but \fIip\fR may be specified to listen only for connections
+to the given \fIip\fR.
 
 .TP
 \fBpunix:\fIfile\fR
index d38ce9e..eb83a5f 100644 (file)
@@ -28,15 +28,16 @@ itself to the background.
 .SH OPTIONS
 .TP
 \fB--accept-vconn=\fIregex\fR
-By default, \fBovs\-discover\fR accepts any controller location
-advertised over DHCP.  With this option, only controllers whose names
-match POSIX extended regular expression \fIregex\fR will be accepted.
-Specifying \fBssl:.*\fR for \fIregex\fR, for example, would cause only
-SSL controller connections to be accepted.
+With this option, only controllers whose names match POSIX extended
+regular expression \fIregex\fR will be accepted.  Specifying
+\fBssl:.*\fR for \fIregex\fR, for example, would cause only SSL
+controller connections to be accepted.
 
 The \fIregex\fR is implicitly anchored at the beginning of the
 controller location string, as if it begins with \fB^\fR.
 
+When this option is not given, the default \fIregex\fR is
+\fBtcp:.*\fR.
 .TP
 \fB--exit-without-bind\fR
 By default, \fBovs\-discover\fR binds the network device that receives
index 0474105..8c83cac 100644 (file)
@@ -48,7 +48,7 @@ static int n_ifaces;
 
 /* --accept-vconn: Regular expression specifying the class of controller vconns
  * that we will accept during autodiscovery. */
-static const char *accept_controller_re = ".*";
+static const char *accept_controller_re = "tcp:.*";
 static regex_t accept_controller_regex;
 
 /* --exit-without-bind: Exit after discovering the controller, without binding
index 81e007f..8812c65 100644 (file)
@@ -410,8 +410,8 @@ the regular expression will be accepted.
 .IP
 The default regular expression is \fBssl:.*\fR, meaning that only SSL
 controller connections will be accepted, when SSL is configured (see
-\fBSSL Configuration\fR), and \fB.*\fR otherwise, meaning that any
-controller will be accepted.
+\fBSSL Configuration\fR), and \fBtcp:.*\fR otherwise, meaning that only
+TCP controller connections will be accepted.
 .IP
 The regular expression is implicitly anchored at the beginning of the
 controller location string, as if it begins with \fB^\fR.
@@ -618,8 +618,11 @@ Listens for connections on the Unix domain server socket named \fIfile\fR.
 Listens for SSL connections on \fIport\fR (default: 6633).  SSL must
 be configured when this form is used (see \fBSSL Configuration\fR,
 above).
-.IP "\fBptcp:\fR[\fIport\fR]"
+.IP "\fBptcp:\fR[\fIport\fR][\fB:\fIip\fR]"
 Listens for TCP connections on \fIport\fR (default: 6633).
+By default, \fB\ovs\-vswitchd\fR listens for connections to any local
+IP address, but \fIip\fR may be specified to limit connections to the
+specified local \fIip\fR.
 .RE
 To entirely disable listening for management connections, set
 \fBbridge.\fIname\fB.openflow.listeners\fR to the single value
index ee3fce3..05f9be9 100644 (file)
@@ -84,6 +84,7 @@ rm -rf \
     $RPM_BUILD_ROOT/root/vswitch/bin/ovs-switchui \
     $RPM_BUILD_ROOT/root/vswitch/bin/ovs-wdt \
     $RPM_BUILD_ROOT/root/vswitch/bin/secchan \
+    $RPM_BUILD_ROOT/root/vswitch/kernel_modules/veth_mod.ko \
     $RPM_BUILD_ROOT/root/vswitch/sbin/ovs-monitor \
     $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-controller.8 \
     $RPM_BUILD_ROOT/root/vswitch/share/man/man8/ovs-discover.8 \
@@ -287,7 +288,6 @@ fi
 /etc/profile.d/vswitch.sh
 /root/vswitch/kernel_modules/brcompat_mod.ko
 /root/vswitch/kernel_modules/openvswitch_mod.ko
-/root/vswitch/kernel_modules/veth_mod.ko
 /root/vswitch/scripts/dump-vif-details
 /root/vswitch/scripts/interface-reconfigure
 /root/vswitch/scripts/vif