Bug Reporting
-------------
-Please report problems to ovs-bugs@openvswitch.org.
+Please report problems to bugs@openvswitch.org.
Reporting Bugs
--------------
-Please report problems to ovs-bugs@openvswitch.org.
+Please report problems to bugs@openvswitch.org.
Reporting Bugs
--------------
-Please report problems to ovs-bugs@openvswitch.org.
+Please report problems to bugs@openvswitch.org.
What is Open vSwitch?
---------------------
-Open vSwitch is an Ethernet switch for virtual servers with the
+Open vSwitch is a versatile software-based Ethernet switch with the
following features:
* NIC bonding with automatic fail-over and source MAC-based TX
* NetFlow v5 flow logging.
- * Connectivity to an external OpenFlow controller, such as
- NOX.
+ * Connectivity to an external OpenFlow controller, such as NOX.
Open vSwitch supports Linux 2.6.15 and up, with testing focused on
2.6.18 with Centos and Xen patches and version 2.6.26 from kernel.org.
The main components of this distribution are:
- - ovs-vswitchd, a daemon that implements the virtual switch,
- along with a companion Linux kernel module for flow-based
- switching.
+ * ovs-vswitchd, a daemon that implements the switch, along with
+ a companion Linux kernel module for flow-based switching.
- - ovs-brcompatd, a daemon that allows ovs-vswitchd to act as a
- drop-in replacement for the Linux bridge in many
- environments, along with a companion Linux kernel module to
- intercept bridge ioctls.
+ * ovs-brcompatd, a daemon that allows ovs-vswitchd to act as a
+ drop-in replacement for the Linux bridge in many environments,
+ along with a companion Linux kernel module to intercept bridge
+ ioctls.
- - ovs-dpctl, a tool for configuring the virtual switch kernel
- module.
+ * ovs-dpctl, a tool for configuring the switch kernel module.
- - Scripts and specs for building RPMs that allow Open vSwitch
- to be installed on a Citrix XenServer host as a drop-in
- replacement for its virtual switch, with additional
- functionality.
+ * Scripts and specs for building RPMs that allow Open vSwitch
+ to be installed on a Citrix XenServer host as a drop-in
+ replacement for its switch, with additional functionality.
- - vlog-appctl, a utility that can control Open vSwitch daemons,
- adjusting their logging levels among other uses.
+ * vlog-appctl, a utility that can control Open vSwitch daemons,
+ adjusting their logging levels among other uses.
Open vSwitch also provides an OpenFlow implementation and tools for
those interested in OpenFlow but not additional Open vSwitch features:
- - secchan, a program that implements a simple OpenFlow switch
- (without the special features provided by ovs-vswitchd) using
- the same kernel module as ovs-vswitchd.
+ * secchan, a program that implements a simple OpenFlow switch
+ (without the special features provided by ovs-vswitchd) using
+ the same kernel module as ovs-vswitchd.
- - ovs-controller, a simple OpenFlow controller.
+ * ovs-controller, a simple OpenFlow controller.
- - ovs-ofctl, a utility for querying and controlling OpenFlow
- switches and controllers.
+ * ovs-ofctl, a utility for querying and controlling OpenFlow
+ switches and controllers.
- - ovs-pki, a utility for creating and managing the public-key
- infrastructure for OpenFlow switches.
+ * ovs-pki, a utility for creating and managing the public-key
+ infrastructure for OpenFlow switches.
- - A patch to tcpdump that enables it to parse OpenFlow
- messages.
+ * A patch to tcpdump that enables it to parse OpenFlow messages.
What other documentation is available?
--------------------------------------
Contact
-------
-ovs-bugs@openvswitch.org
+bugs@openvswitch.org
http://openvswitch.org/
# limitations under the License.
AC_PREREQ(2.60)
-AC_INIT(openvswitch, 0.90.0, ovs-bugs@openvswitch.org)
+AC_INIT(openvswitch, 0.90.1, bugs@openvswitch.org)
NX_BUILDNR
AC_CONFIG_SRCDIR([datapath/datapath.c])
AC_CONFIG_MACRO_DIR([m4])
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 */
#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))
{
}
-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));
#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",
#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",
#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));
#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));
}
-static ssize_t store_stp_state(struct class_device *d,
+static ssize_t store_stp_state(DEVICE_PARAMS,
const char *buf,
size_t len)
{
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));
#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);
}
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;
}
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);
}
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);
}
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);
}
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));
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));
}
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));
}
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));
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));
}
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));
#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));
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
};
*/
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);
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;
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);
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; }
kfree(p);
return 0;
}
-#endif /* !SUPPORT_SYSFS */
+#endif /* !CONFIG_SYSFS */
#include "brc_sysfs.h"
#include "datapath.h"
-#ifdef SUPPORT_SYSFS
+#ifdef CONFIG_SYSFS
struct brport_attribute {
struct attribute attr;
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;
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;
err_del:
kobject_del(&p->kobj);
-err_put:
kobject_put(&p->kobj);
+err:
return err;
}
return 0;
}
-#endif /* SUPPORT_SYSFS */
+#endif /* CONFIG_SYSFS */
{
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;
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
kfree_skb(skb);
goto errout;
}
- err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+ rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+ return;
errout:
if (err < 0)
rtnl_set_sk_err(net, RTNLGRP_LINK, err);
struct net_bridge_port *p, *n;
int i;
+ list_for_each_entry_safe (p, n, &dp->port_list, node)
+ if (p->port_no != ODPP_LOCAL)
+ dp_del_port(p, dp_devs);
+
if (dp_del_dp_hook)
dp_del_dp_hook(dp);
- /* Drop references to DP. */
- list_for_each_entry_safe (p, n, &dp->port_list, node)
- dp_del_port(p, dp_devs);
-
rcu_assign_pointer(dps[dp->dp_idx], NULL);
- synchronize_rcu();
- /* Wait until no longer in use, then destroy it. */
- synchronize_rcu();
+ dp_del_port(dp->ports[ODPP_LOCAL], dp_devs);
+
dp_table_destroy(dp->table, 1);
+
for (i = 0; i < DP_N_QUEUES; i++)
skb_queue_purge(&dp->queues[i]);
for (i = 0; i < DP_MAX_GROUPS; i++)
{
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--;
#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. */
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,
ssize_t openvswitch_read(struct file *f, char __user *buf, size_t nbytes,
loff_t *ppos)
{
+ /* XXX is there sufficient synchronization here? */
int listeners = (int) f->private_data;
int dp_idx = iminor(f->f_dentry->d_inode);
struct datapath *dp = get_dp(dp_idx);
static unsigned int openvswitch_poll(struct file *file, poll_table *wait)
{
+ /* XXX is there sufficient synchronization here? */
int dp_idx = iminor(file->f_dentry->d_inode);
struct datapath *dp = get_dp(dp_idx);
unsigned int mask;
#include <linux/netdevice.h>
#include <linux/workqueue.h>
#include <linux/skbuff.h>
+#include <linux/version.h>
#include "flow.h"
#include "brc_sysfs.h"
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;
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. */
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 \
--- /dev/null
+#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 */
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)
#include_next <linux/rtnetlink.h>
#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-static inline int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid,
+static inline void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid,
u32 group, struct nlmsghdr *nlh, gfp_t flags)
{
BUG_ON(nlh); /* not implemented */
/* errors reported via destination sk->sk_err */
nlmsg_multicast(rtnl, skb, 0, group);
}
- return 0;
}
static inline void rtnl_set_sk_err(struct net *net, u32 group, int error)
netlink_set_err(rtnl, 0, group, error);
}
#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
+/* No 'net' parameter in these versions. */
#define rtnl_notify(skb, net, pid, group, nlh, flags) \
- ((void) (net), rtnl_notify(skb, pid, group, nlh, flags))
+ ((void) (net), (void) rtnl_notify(skb, pid, group, nlh, flags))
#define rtnl_set_sk_err(net, group, error) \
((void) (net), rtnl_set_sk_err(group, error))
-#endif /* linux kernel < 2.6.25 */
+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,30)
+/* Make the return type effectively 'void' to match Linux 2.6.30+. */
+#define rtnl_notify(skb, net, pid, group, nlh, flags) \
+ ((void) rtnl_notify(skb, net, pid, group, nlh, flags))
+#endif
#endif /* linux/rtnetlink.h wrapper */
* Development version.
- -- Open vSwitch developers <ovs-dev@openvswitch.org> Mon, 19 Nov 2007 14:57:52 -0800
+ -- Open vSwitch developers <dev@openvswitch.org> Mon, 19 Nov 2007 14:57:52 -0800
Source: openvswitch
Section: net
Priority: extra
-Maintainer: Open vSwitch developers <ovs-dev@openvswitch.org>
+Maintainer: Open vSwitch developers <dev@openvswitch.org>
Build-Depends: debhelper (>= 5), autoconf (>= 2.60), automake1.10, libssl-dev, pkg-config (>= 0.21), po-debconf, bzip2, openssl, libncurses5-dev, libpcre3-dev
Standards-Version: 3.7.3
from it using module-assistant or make-kpkg. README.Debian in this
package provides further instructions.
.
- Open vSwitch is a software-based Ethernet switch targeted at virtual
- servers.
+ Open vSwitch is a full-featured software-based Ethernet switch.
Package: openvswitch-common
Architecture: any
openvswitch-common provides components required by both openvswitch-switch
and openvswitch-controller.
.
- Open vSwitch is a software-based Ethernet switch targeted at virtual
- servers.
+ Open vSwitch is a full-featured software-based Ethernet switch.
Package: openvswitch-switch
Architecture: any
openvswitch-switch provides the userspace components and utilities for
the Open vSwitch kernel-based switch.
.
- Open vSwitch is a software-based Ethernet switch targeted at virtual
- servers.
+ Open vSwitch is a full-featured software-based Ethernet switch.
Package: openvswitch-switch-config
Architecture: any
openvswitch-switch-config provides a utility for interactively configuring
the Open vSwitch switch provided in the openvswitch-switch package.
.
- Open vSwitch is a software-based Ethernet switch targeted at virtual
- servers.
+ Open vSwitch is a full-featured software-based Ethernet switch.
Package: openvswitch-switchui
Architecture: any
Open vSwitch switches and controllers, reducing the risk of
man-in-the-middle attacks on the Open vSwitch network infrastructure.
.
- Open vSwitch is a software-based Ethernet switch targeted at virtual
- servers.
+ Open vSwitch is a full-featured software-based Ethernet switch.
Package: openvswitch-pki-server
Architecture: all
convenient OpenFlow switch setup using the ovs-switch-setup program
in the openvswitch-switch package.
.
- Open vSwitch is a software-based Ethernet switch targeted at virtual
- servers.
+ Open vSwitch is a full-featured software-based Ethernet switch.
Package: openvswitch-controller
Architecture: any
The Open vSwitch controller enables OpenFlow switches that connect to it
to act as MAC-learning Ethernet switches.
.
- Open vSwitch is a software-based Ethernet switch targeted at virtual
- servers.
+ Open vSwitch is a full-featured software-based Ethernet switch.
Package: corekeeper
Architecture: all
Source: openvswitch
Section: net
Priority: extra
-Maintainer: Open vSwitch developers <ovs-dev@openvswitch.org>
+Maintainer: Open vSwitch developers <dev@openvswitch.org>
Build-Depends: debhelper (>= 5.0.37)
Standards-Version: 3.7.3
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
-"Report-Msgid-Bugs-To: ovs-dev@openvswitch.org\n"
+"Report-Msgid-Bugs-To: dev@openvswitch.org\n"
"POT-Creation-Date: 2009-05-11 13:38-0700\n"
"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
peer ? peer : &dummy[3]);
}
+/* Set the features advertised by 'netdev' to 'advertise'. */
int
netdev_set_advertisements(struct netdev *netdev, uint32_t advertise)
{
return ENODEV;
}
+/* Sets 'carrier' to true if carrier is active (link light is on) on
+ * 'netdev'. */
int
netdev_get_carrier(const struct netdev *netdev, bool *carrier)
{
return error;
}
+/* Retrieves current device stats for 'netdev'. */
int
netdev_get_stats(const struct netdev *netdev, struct netdev_stats *stats)
{
#include <poll.h>
#include <stddef.h>
#include <stdio.h>
+#include <stdlib.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/un.h>
: 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)
{
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);
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;
}
}
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);
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;
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;
}
}
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
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) {
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);
}
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 "
if (retval != EAGAIN) {
vconn->state = VCS_DISCONNECTED;
- vconn->error = retval;
+ vconn->error = retval == EOF ? ECONNRESET : retval;
}
}
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;
&& 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",
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);
/* 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. */
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.
.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
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)
+
--- /dev/null
+/*
+ * Copyright (c) 2009 Nicira Networks.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at:
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#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;
+}
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
.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
/* --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
-.TH ovs\-ofctl 8 "March 2009" "Open vSwitch" "Open vSwitch Manual"
+.TH ovs\-ofctl 8 "June 2009" "Open vSwitch" "Open vSwitch Manual"
.ds PN ovs\-ofctl
.SH NAME
displayed by \fBovs\-ofctl show\fR.
.IP \fBdl_vlan=\fIvlan\fR
-Matches IEEE 802.1q virtual LAN tag \fIvlan\fR. Specify \fB0xffff\fR
-as \fIvlan\fR to match packets that are not tagged with a virtual LAN;
+Matches IEEE 802.1q Virtual LAN tag \fIvlan\fR. Specify \fB0xffff\fR
+as \fIvlan\fR to match packets that are not tagged with a Virtual LAN;
otherwise, specify a number between 0 and 4095, inclusive, as the
12-bit VLAN ID to match.
-.TH ovs\-vswitchd 8 "March 2009" "Open vSwitch" "OpenVSwitch Manual"
+.TH ovs\-vswitchd 8 "June 2009" "Open vSwitch" "Open vSwitch Manual"
.ds PN ovs\-vswitchd
.
.SH NAME
-ovs\-vswitchd \- virtual switch daemon
+ovs\-vswitchd \- Open vSwitch daemon
.
.SH SYNOPSIS
.B ovs\-vswitchd
\fIconfig\fR
.
.SH DESCRIPTION
-A daemon that manages and controls any number of virtual switches on
-the local machine.
+A daemon that manages and controls any number of Open vSwitch switches
+on the local machine.
.PP
The mandatory \fIconfig\fR argument specifies a configuration file.
For a description of \fBovs\-vswitchd\fR configuration syntax, see
files. If a logfile was specified on the command line it will also
be opened or reopened.
.PP
-\fBovs\-vswitchd\fR virtual switches may be configured with any of the
-following features:
+\fBovs\-vswitchd\fR switches may be configured with any of the following
+features:
.
.IP \(bu
L2 switching with MAC learning.
.
.PP
Only a single instance of \fBovs\-vswitchd\fR is intended to run at a time.
-A single \fBovs\-vswitchd\fR can manage any number of virtual switches, up
+A single \fBovs\-vswitchd\fR can manage any number of switch instances, up
to the maximum number of supported Open vSwitch datapaths.
.PP
-\fBovs\-vswitchd\fR does all the necessary management of OpenVSwitch datapaths
+\fBovs\-vswitchd\fR does all the necessary management of Open vSwitch datapaths
itself. Thus, external tools, such \fBovs\-dpctl\fR(8), are not needed for
managing datapaths in conjunction with \fBovs\-vswitchd\fR, and their use
to modify datapaths when \fBovs\-vswitchd\fR is running can interfere with
static void
usage(void)
{
- printf("%s: virtual switch daemon\n"
+ printf("%s: Open vSwitch daemon\n"
"usage: %s [OPTIONS] CONFIG\n"
"CONFIG is a configuration file in ovs-vswitchd.conf(5) format.\n",
program_name, program_name);
. RE
. PP
..
-.TH ovs\-vswitchd.conf 5 "April 2009" "Open vSwitch" "OpenVSwitch Manual"
+.TH ovs\-vswitchd.conf 5 "June 2009" "Open vSwitch" "Open vSwitch Manual"
.
.SH NAME
ovs\-vswitchd.conf \- configuration file for \fBovs\-vswitchd\fR
.
.SH DESCRIPTION
This manual page describes the syntax for the configuration file used
-by \fBovs\-vswitchd\fR(8), the virtual switch daemon.
+by \fBovs\-vswitchd\fR(8), the Open vSwitch daemon.
.PP
The configuration file is based on key-value pairs, which are given
one per line in the form \fIkey\fB=\fIvalue\fR. Each \fIkey\fR
The names given on \fBbridge.\fIname\fB.port\fR must be the names of
existing network devices, except for ``internal ports.'' An internal
port is a simulated network device that receives traffic only
-through the virtual switch and switches any traffic sent it through
-virtual switch. An internal port may configured with an IP address,
+through the switch and switches any traffic sent it through the
+switch. An internal port may configured with an IP address,
etc. using the usual system tools (e.g. \fBifconfig\fR, \fBip\fR). To
designate network device \fInetdev\fR as an internal port, add
\fBiface.\fInetdev\fB.internal=true\fR to the configuration file.
\fBnetflow.\fIbridge\fB.engine-id\fR, respectively. Each takes a value
between 0 and 255, inclusive.
-Many NetFlow collectors do not expect multiple virtual switches to be
+Many NetFlow collectors do not expect multiple switches to be
sending messages from the same host, and they do not store the engine
information which could be used to disambiguate the traffic. To prevent
flows from multiple switches appearing as if they came on the interface,
.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.
The minimum value of \fIsecs\fR is 5 seconds. The default is taken
from \fBmgmt.inactivity-probe\fR (see above).
.IP
-When the virtual switch is connected to the controller, it waits for a
+When the switch is connected to the controller, it waits for a
message to be received from the controller for \fIsecs\fR seconds
before it sends a inactivity probe to the controller. After sending
the inactivity probe, if no response is received for an additional
.IP "\fBbridge.\fIname\fB.controller.fail-mode=\fBstandalone\fR|\fBsecure\fR"
.IQ "\fBmgmt.fail-mode=standalone\fR|\fBsecure\fR"
When a controller is configured, it is, ordinarily, responsible for
-setting up all flows on the virtual switch. Thus, if the connection to
+setting up all flows on the switch. Thus, if the connection to
the controller fails, no new network connections can be set up. If
the connection to the controller stays down long enough, no packets
can pass through the switch at all.
attempt until it reaches the maximum. The default maximum backoff
time is taken from \fBmgmt.max-backoff\fR.
.ST "Controller Rate-Limiting"
-These settings configure how the virtual switch applies a ``token
+These settings configure how the switch applies a ``token
bucket'' to limit the rate at which packets in unknown flows are
forwarded to the OpenFlow controller for flow-setup processing. This
feature prevents a single bridge from overwhelming a controller.
for controller connectivity, the following settings are required:
.TP
\fBssl.private-key=\fIprivkey.pem\fR
-Specifies a PEM file containing the private key used as the virtual
+Specifies a PEM file containing the private key used as the
switch's identity for SSL connections to the controller.
.TP
\fBssl.certificate=\fIcert.pem\fR
Specifies a PEM file containing a certificate, signed by the
certificate authority (CA) used by the controller and manager, that
-certifies the virtual switch's private key, identifying a trustworthy
+certifies the switch's private key, identifying a trustworthy
switch.
.TP
\fBssl.ca-cert=\fIcacert.pem\fR
Specifies a PEM file containing the CA certificate used to verify that
-the virtual switch is connected to a trustworthy controller.
+the switch is connected to a trustworthy controller.
.PP
These files are read only once, at \fBovs\-vswitchd\fR startup time. If
their contents change, \fBovs\-vswitchd\fR must be killed and restarted.
.PP
-These SSL settings apply to all SSL connections made by the virtual
-switch.
+These SSL settings apply to all SSL connections made by the switch.
.ST "CA Certificate Bootstrap"
Ordinarily, all of the files named in the SSL configuration must exist
when \fBovs\-vswitchd\fR starts. However, if \fBssl.bootstrap-ca-cert\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
$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 \
/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