skb_queue_head_init(&dp->queues[i]);
init_waitqueue_head(&dp->waitqueue);
- kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR); /* "bridge" */
+ /* Initialize kobject for bridge. This will be added as
+ * /sys/class/net/<devname>/bridge later, if sysfs is enabled. */
- dp->ifobj.parent = NULL;
+ dp->ifobj.kset = NULL;
+ kobject_init(&dp->ifobj, &dp_ktype);
+
/* Allocate table. */
err = -ENOMEM;
rcu_assign_pointer(dp->table, dp_table_create(DP_L1_SIZE));
mutex_unlock(&dp_mutex);
rtnl_unlock();
- #ifdef SUPPORT_SYSFS
- if (dp_add_dp_hook)
- dp_add_dp_hook(dp);
+ dp_sysfs_add_dp(dp);
- #endif
return 0;
if (p->port_no != ODPP_LOCAL)
dp_del_port(p);
- #ifdef SUPPORT_SYSFS
- if (dp_del_dp_hook)
- dp_del_dp_hook(dp);
+ dp_sysfs_del_dp(dp);
- #endif
rcu_assign_pointer(dps[dp->dp_idx], NULL);
return err;
}
- #ifdef SUPPORT_SYSFS
+static void release_nbp(struct kobject *kobj)
+{
+ struct net_bridge_port *p = container_of(kobj, struct net_bridge_port, kobj);
+ kfree(p);
+}
+
+struct kobj_type brport_ktype = {
++#ifdef CONFIG_SYSFS
+ .sysfs_ops = &brport_sysfs_ops,
+#endif
+ .release = release_nbp
+};
+
/* Called with RTNL lock and dp_mutex. */
static int new_nbp(struct datapath *dp, struct net_device *dev, int port_no)
{
list_add_rcu(&p->node, &dp->port_list);
dp->n_ports++;
- kobject_set_name(&p->kobj, SYSFS_BRIDGE_PORT_ATTR); /* "brport" */
+ /* Initialize kobject for bridge. This will be added as
+ * /sys/class/net/<devname>/brport later, if sysfs is enabled. */
- p->kobj.parent = &p->dev->NETDEV_DEV_MEMBER.kobj;
+ p->kobj.kset = NULL;
+ kobject_init(&p->kobj, &brport_ktype);
+
dp_ifinfo_notify(RTM_NEWLINK, p);
return 0;
if (err)
goto out_put;
- #ifdef SUPPORT_SYSFS
- if (dp_add_if_hook)
- dp_add_if_hook(dp->ports[port_no]);
+ dp_sysfs_add_if(dp->ports[port_no]);
- #endif
+
+ err = __put_user(port_no, &port.port);
out_put:
dev_put(dev);
{
ASSERT_RTNL();
- #ifdef SUPPORT_SYSFS
- 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
- }
+ if (p->port_no != ODPP_LOCAL)
+ dp_sysfs_del_if(p);
- #endif
dp_ifinfo_notify(RTM_DELLINK, p);
p->dp->n_ports--;
#include <linux/netdevice.h>
#include <linux/workqueue.h>
#include <linux/skbuff.h>
+ #include <linux/version.h>
#include "flow.h"
-#include "brc_sysfs.h"
+#include "dp_sysfs.h"
/* Mask for the priority bits in a vlan header. If we ever merge upstream
* then this should go into include/linux/if_vlan.h. */
--- /dev/null
- #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
-
- #ifdef SUPPORT_SYSFS
+/*
+ * Copyright (c) 2009 Nicira Networks.
+ * Distributed under the terms of the GNU GPL version 2.
+ *
+ * Significant portions of this file may be copied from parts of the Linux
+ * kernel, by Linus Torvalds and others.
+ */
+
+#ifndef DP_SYSFS_H
+#define DP_SYSFS_H 1
+
+struct datapath;
+struct net_bridge_port;
+
+/* dp_sysfs_dp.c */
+int dp_sysfs_add_dp(struct datapath *dp);
+int dp_sysfs_del_dp(struct datapath *dp);
+
+/* dp_sysfs_if.c */
+int dp_sysfs_add_if(struct net_bridge_port *p);
+int dp_sysfs_del_if(struct net_bridge_port *p);
+
++#ifdef CONFIG_SYSFS
+extern struct sysfs_ops brport_sysfs_ops;
+#endif
+
+#endif /* dp_sysfs.h */
+
/* 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 DP_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 DP_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
/*
#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,
+static DP_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",
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,
+static DP_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 DP_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,
+static DP_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));
return len;
}
-static BRC_DEVICE_ATTR(stp_state, S_IRUGO | S_IWUSR, show_stp_state,
+static DP_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 DP_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);
return sprintf(buf, "0000.010203040506\n");
#endif
}
-static BRC_DEVICE_ATTR(root_id, S_IRUGO, show_root_id, NULL);
+static DP_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;
return sprintf(buf, "%.2x%.2x.%.2x%.2x%.2x%.2x%.2x%.2x\n",
0, 0, addr[0], addr[1], addr[2], addr[3], addr[4], addr[5]);
}
-static BRC_DEVICE_ATTR(bridge_id, S_IRUGO, show_bridge_id, NULL);
+static DP_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);
return sprintf(buf, "%d\n", 0);
#endif
}
-static BRC_DEVICE_ATTR(root_port, S_IRUGO, show_root_port, NULL);
+static DP_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);
return sprintf(buf, "%d\n", 0);
#endif
}
-static BRC_DEVICE_ATTR(root_path_cost, S_IRUGO, show_root_path_cost, NULL);
+static DP_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);
return sprintf(buf, "%d\n", 0);
#endif
}
-static BRC_DEVICE_ATTR(topology_change, S_IRUGO, show_topology_change, NULL);
+static DP_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));
return sprintf(buf, "%d\n", 0);
#endif
}
-static BRC_DEVICE_ATTR(topology_change_detected, S_IRUGO,
+static DP_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));
return sprintf(buf, "%d\n", 0);
#endif
}
-static BRC_DEVICE_ATTR(hello_timer, S_IRUGO, show_hello_timer, NULL);
+static DP_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));
return sprintf(buf, "%d\n", 0);
#endif
}
-static BRC_DEVICE_ATTR(tcn_timer, S_IRUGO, show_tcn_timer, NULL);
+static DP_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));
return sprintf(buf, "%d\n", 0);
#endif
}
-static BRC_DEVICE_ATTR(topology_change_timer, S_IRUGO, show_topology_change_timer,
+static DP_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));
return sprintf(buf, "%d\n", 0);
#endif
}
-static BRC_DEVICE_ATTR(gc_timer, S_IRUGO, show_gc_timer, NULL);
+static DP_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));
* to hold links. The ifobj exists in the same data structure
* as its parent the bridge so reference counting works.
*/
-int brc_sysfs_add_dp(struct datapath *dp)
+int dp_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);
goto out1;
}
- /* Create /sys/class/net/<devname>/bridge directory. */
-#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
- kobject_set_name(&dp->ifobj, SYSFS_BRIDGE_PORT_SUBDIR);
- dp->ifobj.ktype = NULL;
- dp->ifobj.kset = NULL;
-- dp->ifobj.parent = kobj;
- err = kobject_add(&dp->ifobj);
-
- err = kobject_register(&dp->ifobj);
++ /* Create /sys/class/net/<devname>/brif directory. */
++ err = kobject_add(&dp->ifobj, kobj, SYSFS_BRIDGE_PORT_SUBDIR);
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
- 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;
- }
-#endif
+ kobject_uevent(&dp->ifobj, KOBJ_ADD);
return 0;
out2:
return err;
}
-int brc_sysfs_del_dp(struct datapath *dp)
+int dp_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);
-#else
- kobject_put(dp->ifobj);
-#endif
+ kobject_del(&dp->ifobj);
sysfs_remove_group(kobj, &bridge_group);
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; }
-int brc_sysfs_del_if(struct net_bridge_port *p)
-{
- dev_put(p->dev);
- kfree(p);
- return 0;
-}
+int dp_sysfs_add_dp(struct datapath *dp) { return 0; }
+int dp_sysfs_del_dp(struct datapath *dp) { return 0; }
+int dp_sysfs_add_if(struct net_bridge_port *p) { return 0; }
- int dp_sysfs_del_if(struct net_bridge_port *p)
- {
- dev_put(p->dev);
- kfree(p);
- return 0;
- }
- #endif /* !SUPPORT_SYSFS */
++int dp_sysfs_del_if(struct net_bridge_port *p) { return 0; }
+ #endif /* !CONFIG_SYSFS */
#include <linux/if_bridge.h>
#include <linux/rtnetlink.h>
#include <linux/spinlock.h>
-#include "brc_sysfs.h"
+#include "dp_sysfs.h"
#include "datapath.h"
- #ifdef SUPPORT_SYSFS
+ #ifdef CONFIG_SYSFS
struct brport_attribute {
struct attribute attr;
struct brport_attribute **a;
int err;
- err = kobject_init_and_add(&p->kobj, &brport_ktype,
- &(p->dev->NETDEV_DEV_MEMBER.kobj),
- SYSFS_BRIDGE_PORT_ATTR);
+ /* Create /sys/class/net/<devname>/brport directory. */
- err = kobject_add(&p->kobj);
++ err = kobject_add(&p->kobj, &p->dev->NETDEV_DEV_MEMBER.kobj,
++ SYSFS_BRIDGE_PORT_ATTR);
if (err)
- goto err_put;
+ goto err;
+ /* Create symlink from /sys/class/net/<devname>/brport/bridge to
+ * /sys/class/net/<bridgename>. */
err = sysfs_create_link(&p->kobj,
&dp->ports[ODPP_LOCAL]->dev->NETDEV_DEV_MEMBER.kobj,
- SYSFS_BRIDGE_PORT_LINK);
+ SYSFS_BRIDGE_PORT_LINK); /* "bridge" */
if (err)
goto err_del;
kobject_uevent(&p->kobj, KOBJ_ADD);
-- return err;
++ return 0;
err_del:
kobject_del(&p->kobj);
- err_put:
-- kobject_put(&p->kobj);
-
- /* Ensure that dp_sysfs_del_if becomes a no-op. */
- p->kobj.dentry = NULL;
+ err:
++ p->linkname[0] = 0;
return err;
}
-int brc_sysfs_del_if(struct net_bridge_port *p)
+int dp_sysfs_del_if(struct net_bridge_port *p)
{
- struct net_device *dev = p->dev;
-
- kobject_uevent(&p->kobj, KOBJ_REMOVE);
- kobject_del(&p->kobj);
-
- dev_put(dev);
-
- kobject_put(&p->kobj);
-
+ if (p->linkname[0]) {
+ sysfs_remove_link(&p->dp->ifobj, p->linkname);
- p->linkname[0] = '\0';
- }
- if (p->kobj.dentry) {
+ kobject_uevent(&p->kobj, KOBJ_REMOVE);
+ kobject_del(&p->kobj);
++ p->linkname[0] = '\0';
+ }
return 0;
}
- #endif /* SUPPORT_SYSFS */
+ #endif /* CONFIG_SYSFS */
#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)
+#define kobject_init(kobj, ktype) rpl_kobject_init(kobj, ktype)
+static inline void rpl_kobject_init(struct kobject *kobj, struct kobj_type *ktype)
{
- kobject_init(kobj);
- kobject_set_name(kobj, "%s", name);
kobj->ktype = ktype;
- kobj->kset = NULL;
- kobj->parent = parent;
+ (kobject_init)(kobj);
+}
+
- return kobject_add(kobj);
++#define kobject_add(kobj, parent, name) rpl_kobject_add(kobj, parent, name)
++static inline int rpl_kobject_add(struct kobject *kobj,
++ struct kobject *parent,
++ const char *name)
++{
++ int err = kobject_set_name(kobj, "%s", name);
++ if (err)
++ return err;
++ kobj->parent = parent;
++ return (kobject_add)(kobj);
+ }
#endif
++
#endif /* linux/kobject.h wrapper */
#RATE_LIMIT=1000
# INACTIVITY_PROBE: The maximum number of seconds of inactivity on the
- # controller connection before secchan sends an inactivity probe
+ # controller connection before ovs-openflowd sends an inactivity probe
# message to the controller. The valid range is 5 and up. If unset,
- # secchan defaults to 5 seconds.
-# ovs-openflowd defaults to 15 seconds.
++# ovs-openflowd defaults to 5 seconds.
#INACTIVITY_PROBE=5
- # MAX_BACKOFF: The maximum time that secchan will wait between
+ # MAX_BACKOFF: The maximum time that ovs-openflowd will wait between
# attempts to connect to the controller. The valid range is 1 and up.
- # If unset, secchan defaults to 8 seconds.
-# If unset, ovs-openflowd defaults to 15 seconds.
-#MAX_BACKOFF=15
++# If unset, ovs-openflowd defaults to 8 seconds.
+#MAX_BACKOFF=8
- # DAEMON_OPTS: Additional options to pass to secchan, e.g. "--fail=open"
+ # DAEMON_OPTS: Additional options to pass to ovs-openflowd, e.g. "--fail=open"
DAEMON_OPTS=""
# CORE_LIMIT: Maximum size for core dumps.
flow_extract(&b, 0, &flow);
if (flow.dl_type != htons(ETH_TYPE_IP)
|| flow.nw_proto != IP_TYPE_UDP
- || flow.tp_dst != htons(68)
+ || flow.tp_dst != htons(DHCP_CLIENT_PORT)
|| !(eth_addr_is_broadcast(flow.dl_dst)
- || eth_addr_equals(flow.dl_dst,
- netdev_get_etheraddr(cli->netdev)))) {
+ || eth_addr_equals(flow.dl_dst, cli_mac))) {
continue;
}
int error;
COVERAGE_INC(ofproto_update_port);
- ofport = shash_find_data(&p->port_by_name, devname);
+
+ /* Query the datapath for port information. */
- error = dpif_port_query_by_name(&p->dpif, devname, &odp_port);
+ error = dpif_port_query_by_name(p->dpif, devname, &odp_port);
- if (!error) {
- if (!ofport) {
- /* New port. */
- if (!ofport_conflicts(p, &odp_port)) {
- ofport = make_ofport(&odp_port);
- if (ofport) {
- ofport_install(p, ofport);
- send_port_status(p, ofport, OFPPR_ADD);
- }
- }
- } else {
- /* Modified port. */
- struct ofport *new_ofport = make_ofport(&odp_port);
- if (!new_ofport) {
- return;
- }
- new_ofport->opp.config &= OFPPC_PORT_DOWN;
- new_ofport->opp.config |= ofport->opp.config & ~OFPPC_PORT_DOWN;
- if (ofport_equal(ofport, new_ofport)) {
- /* False alarm--no change. */
- ofport_free(new_ofport);
- } else {
- ofport_remove(p, ofport);
- ofport_install(p, new_ofport);
- ofport_free(ofport);
- send_port_status(p, new_ofport, OFPPR_MODIFY);
- }
- }
- } else if (error == ENOENT || error == ENODEV) {
- /* Deleted port. */
- if (ofport) {
- send_port_status(p, ofport, OFPPR_DELETE);
- ofport_remove(p, ofport);
- ofport_free(ofport);
+ /* Find the old ofport. */
+ old_ofport = shash_find_data(&p->port_by_name, devname);
+ if (!error) {
+ if (!old_ofport) {
+ /* There's no port named 'devname' but there might be a port with
+ * the same port number. This could happen if a port is deleted
+ * and then a new one added in its place very quickly, or if a port
+ * is renamed. In the former case we want to send an OFPPR_DELETE
+ * and an OFPPR_ADD, and in the latter case we want to send a
+ * single OFPPR_MODIFY. We can distinguish the cases by comparing
+ * the old port's ifindex against the new port, or perhaps less
+ * reliably but more portably by comparing the old port's MAC
+ * against the new port's MAC. However, this code isn't that smart
+ * and always sends an OFPPR_MODIFY (XXX). */
+ old_ofport = port_array_get(&p->ports, odp_port.port);
}
- } else {
+ } else if (error != ENOENT && error != ENODEV) {
VLOG_WARN_RL(&rl, "dpif_port_query_by_name returned unexpected error "
"%s", strerror(error));
return;
}
}
- struct dpif dpif;
- char dpif_name[IF_NAMESIZE];
-
- if (dpif_open(all_dps.names[i], &dpif)) {
- continue;
- }
- if (!dpif_get_name(&dpif, dpif_name, sizeof dpif_name)) {
- printf("%s\n", dpif_name);
+static void
+do_dump_dps(int argc UNUSED, char *argv[] UNUSED)
+{
+ struct svec all_dps;
+ unsigned int i;
+ int error;
+
+ svec_init(&all_dps);
+ error = dp_enumerate(&all_dps);
+
+ for (i = 0; i < all_dps.n; i++) {
- dpif_close(&dpif);
++ struct dpif *dpif;
++ if (!dpif_open(all_dps.names[i], &dpif)) {
++ printf("%s\n", dpif_name(dpif));
++ dpif_close(dpif);
+ }
+ }
+
+ svec_destroy(&all_dps);
+ if (error) {
+ exit(EXIT_FAILURE);
+ }
+}
+
static void
do_dump_flows(int argc UNUSED, char *argv[])
{
.TP
\fB--inactivity-probe=\fIsecs\fR
- When the secure channel is connected to the controller, the secure
- channel waits for a message to be received from the controller for
+ When the OpenFlow switch is connected to the controller, the
+ switch 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 \fIsecs\fR seconds, the secure channel
+ received for an additional \fIsecs\fR seconds, the switch
assumes that the connection has been broken and attempts to reconnect.
-The default is 15 seconds, and the minimum value is 5 seconds.
+The default and the minimum value are both 5 seconds.
When fail-open mode is configured, changing the inactivity probe
interval also changes the interval before entering fail-open mode (see
" closed: drop all packets\n"
" open (default): act as learning switch\n"
" --inactivity-probe=SECS time between inactivity probes\n"
- " --max-idle=SECS max idle for flows set up by secchan\n"
+ " --max-idle=SECS max idle for flows set up by switch\n"
" --max-backoff=SECS max time between controller connection\n"
- " attempts (default: 15 seconds)\n"
+ " attempts (default: 8 seconds)\n"
" -l, --listen=METHOD allow management connections on METHOD\n"
" (a passive OpenFlow connection method)\n"
" --snoop=METHOD allow controller snooping on METHOD\n"
}
}
+ unixctl_command_register("bridge/dump-flows", bridge_unixctl_dump_flows);
+
+ bond_init();
bridge_reconfigure();
}
bridge_get_all_ifaces(br, &want_ifaces);
svec_diff(&want_ifaces, &cur_ifaces, &add_ifaces, NULL, NULL);
- next_port_no = 1;
for (i = 0; i < add_ifaces.n; i++) {
const char *if_name = add_ifaces.names[i];
- for (;;) {
- bool internal;
- int error;
-
- /* It's an internal interface if it's marked that way, or if
- * it's a bonded interface for which we're faking up a network
- * device. */
- internal = cfg_get_bool(0, "iface.%s.internal", if_name);
- if (cfg_get_bool(0, "bonding.%s.fake-iface", if_name)) {
- struct port *port = port_lookup(br, if_name);
- if (port && port->n_ifaces > 1) {
- internal = true;
- }
- }
- int internal = cfg_get_bool(0, "iface.%s.internal", if_name);
- int flags = internal ? ODP_PORT_INTERNAL : 0;
- int error = dpif_port_add(br->dpif, if_name, flags, NULL);
++ bool internal;
++ int error;
+
- /* Add to datapath. */
- error = dpif_port_add(&br->dpif, if_name, next_port_no++,
- internal ? ODP_PORT_INTERNAL : 0);
- if (error != EEXIST) {
- if (next_port_no >= 256) {
- VLOG_ERR("ran out of valid port numbers on dp%u",
- dpif_id(&br->dpif));
- goto out;
- }
- if (error) {
- VLOG_ERR("failed to add %s interface to dp%u: %s",
- if_name, dpif_id(&br->dpif), strerror(error));
- }
- break;
++ /* It's an internal interface if it's marked that way, or if
++ * it's a bonded interface for which we're faking up a network
++ * device. */
++ internal = cfg_get_bool(0, "iface.%s.internal", if_name);
++ if (cfg_get_bool(0, "bonding.%s.fake-iface", if_name)) {
++ struct port *port = port_lookup(br, if_name);
++ if (port && port->n_ifaces > 1) {
++ internal = true;
+ }
+ }
++
++ /* Add to datapath. */
++ error = dpif_port_add(br->dpif, if_name,
++ internal ? ODP_PORT_INTERNAL : 0, NULL);
+ if (error == EXFULL) {
+ VLOG_ERR("ran out of valid port numbers on %s",
+ dpif_name(br->dpif));
+ break;
+ } else if (error) {
+ VLOG_ERR("failed to add %s interface to %s: %s",
+ if_name, dpif_name(br->dpif), strerror(error));
+ }
}
- out:
svec_destroy(&cur_ifaces);
svec_destroy(&want_ifaces);
svec_destroy(&add_ifaces);
if (port->is_mirror_output_port) {
continue;
}
- for (j = 0; j < port->n_ifaces; j++) {
- struct iface *iface = port->ifaces[j];
- uint8_t iface_ea[ETH_ADDR_LEN];
+
+ /* Choose the MAC address to represent the port. */
+ iface_ea_u64 = cfg_get_mac(0, "port.%s.mac", port->name);
+ if (iface_ea_u64) {
+ /* User specified explicitly. */
+ eth_addr_from_uint64(iface_ea_u64, iface_ea);
+
+ /* Find the interface with this Ethernet address (if any) so that
+ * we can provide the correct devname to the caller. */
+ iface = NULL;
+ for (j = 0; j < port->n_ifaces; j++) {
+ struct iface *candidate = port->ifaces[j];
+ uint8_t candidate_ea[ETH_ADDR_LEN];
- if (!netdev_nodev_get_etheraddr(candidate->name, candidate_ea)
++ if (!netdev_get_etheraddr(candidate->netdev, candidate_ea)
+ && eth_addr_equals(iface_ea, candidate_ea)) {
+ iface = candidate;
+ }
+ }
+ } else {
+ /* Choose the interface whose MAC address will represent the port.
+ * The Linux kernel bonding code always chooses the MAC address of
+ * the first slave added to a bond, and the Fedora networking
+ * scripts always add slaves to a bond in alphabetical order, so
+ * for compatibility we choose the interface with the name that is
+ * first in alphabetical order. */
+ iface = port->ifaces[0];
+ for (j = 1; j < port->n_ifaces; j++) {
+ struct iface *candidate = port->ifaces[j];
+ if (strcmp(candidate->name, iface->name) < 0) {
+ iface = candidate;
+ }
+ }
+
+ /* The local port doesn't count (since we're trying to choose its
+ * MAC address anyway). Other internal ports don't count because
+ * we really want a physical MAC if we can get it, and internal
+ * ports typically have randomly generated MACs. */
if (iface->dp_ifidx == ODPP_LOCAL
|| cfg_get_bool(0, "iface.%s.internal", iface->name)) {
continue;
}
- error = netdev_nodev_get_etheraddr(iface->name, iface_ea);
+
+ /* Grab MAC. */
- if (!error) {
- if (!eth_addr_is_multicast(iface_ea) &&
- !eth_addr_is_reserved(iface_ea) &&
- !eth_addr_is_zero(iface_ea) &&
- memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0) {
- memcpy(ea, iface_ea, ETH_ADDR_LEN);
- *hw_addr_iface = iface;
- }
- } else {
+ error = netdev_get_etheraddr(iface->netdev, iface_ea);
+ if (error) {
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 5);
VLOG_ERR_RL(&rl, "failed to obtain Ethernet address of %s: %s",
iface->name, strerror(error));
+ continue;
}
}
- memcpy(ea, iface_ea, ETH_ADDR_LEN);
- *devname = iface ? iface->name : NULL;
+
+ /* Compare against our current choice. */
+ if (!eth_addr_is_multicast(iface_ea) &&
+ !eth_addr_is_reserved(iface_ea) &&
+ !eth_addr_is_zero(iface_ea) &&
+ memcmp(iface_ea, ea, ETH_ADDR_LEN) < 0)
+ {
++ *hw_addr_iface = iface;
+ }
}
if (eth_addr_is_multicast(ea) || eth_addr_is_vif(ea)) {
memcpy(ea, br->default_ea, ETH_ADDR_LEN);
if (slave->up) {
bond.up = true;
}
- memcpy(slave->mac, iface->mac, ETH_ADDR_LEN);
+ netdev_get_etheraddr(iface->netdev, slave->mac);
}
+
proc_net_compat_update_bond(port->name, &bond);
free(bond.slaves);
}
}
unixctl_command_register("vswitchd/reload", reload);
- cfg_read();
+ retval = cfg_read();
+ if (retval) {
+ ovs_fatal(retval, "could not read config file");
+ }
mgmt_init();
bridge_init();
- port_init();
mgmt_reconfigure();
need_reconfigure = false;
import traceback
import time
import re
- import pickle
+import random
+ from xml.dom.minidom import getDOMImplementation
+ from xml.dom.minidom import parse as parseXML
output_directory = None
def interface_exists(i):
return os.path.exists("/sys/class/net/" + i)
+def get_netdev_mac(device):
+ try:
+ return read_first_line_of_file("/sys/class/net/%s/address" % device)
+ except:
+ # Probably no such device.
+ return None
+
+def get_netdev_tx_queue_len(device):
+ try:
+ return int(read_first_line_of_file("/sys/class/net/%s/tx_queue_len"
+ % device))
+ except:
+ # Probably no such device.
+ return None
+
+def get_netdev_by_mac(mac):
+ maybe = None
+ for device in os.listdir("/sys/class/net"):
+ dev_mac = get_netdev_mac(device)
+ if dev_mac and mac.lower() == dev_mac.lower():
+ if get_netdev_tx_queue_len(device):
+ return device
+ if not maybe:
+ # Probably a datapath internal port.
+ maybe = device
+ return maybe
+
+ #
+ # Helper functions for encoding/decoding database attributes to/from XML.
+ #
+ def str_to_xml(xml, parent, tag, val):
+ e = xml.createElement(tag)
+ parent.appendChild(e)
+ v = xml.createTextNode(val)
+ e.appendChild(v)
+ def str_from_xml(n):
+ def getText(nodelist):
+ rc = ""
+ for node in nodelist:
+ if node.nodeType == node.TEXT_NODE:
+ rc = rc + node.data
+ return rc
+ return getText(n.childNodes).strip()
+
+
+ def bool_to_xml(xml, parent, tag, val):
+ if val:
+ str_to_xml(xml, parent, tag, "True")
+ else:
+ str_to_xml(xml, parent, tag, "False")
+ def bool_from_xml(n):
+ s = str_from_xml(n)
+ if s == "True":
+ return True
+ elif s == "False":
+ return False
+ else:
+ raise Error("Unknown boolean value %s" % s);
+
+ def strlist_to_xml(xml, parent, ltag, itag, val):
+ e = xml.createElement(ltag)
+ parent.appendChild(e)
+ for v in val:
+ c = xml.createElement(itag)
+ e.appendChild(c)
+ cv = xml.createTextNode(v)
+ c.appendChild(cv)
+ def strlist_from_xml(n, ltag, itag):
+ ret = []
+ for n in n.childNodes:
+ if n.nodeName == itag:
+ ret.append(str_from_xml(n))
+ return ret
+
+ def otherconfig_to_xml(xml, parent, val, attrs):
+ otherconfig = xml.createElement("other_config")
+ parent.appendChild(otherconfig)
+ for n,v in val.items():
+ if not n in attrs:
+ raise Error("Unknown other-config attribute: %s" % n)
+ str_to_xml(xml, otherconfig, n, v)
+ def otherconfig_from_xml(n, attrs):
+ ret = {}
+ for n in n.childNodes:
+ if n.nodeName in attrs:
+ ret[n.nodeName] = str_from_xml(n)
+ return ret
+
+ #
+ # Definitions of the database objects (and their attributes) used by interface-reconfigure.
+ #
+ # Each object is defined by a dictionary mapping an attribute name in
+ # the xapi database to a tuple containing two items:
+ # - a function which takes this attribute and encodes it as XML.
+ # - a function which takes XML and decocdes it into a value.
+ #
+ # other-config attributes are specified as a simple array of strings
+
+ PIF_XML_TAG = "pif"
+ VLAN_XML_TAG = "vlan"
+ BOND_XML_TAG = "bond"
+ NETWORK_XML_TAG = "network"
+
+ ETHTOOL_OTHERCONFIG_ATTRS = ['ethtool-%s' % x for x in 'autoneg', 'speed', 'duplex', 'rx', 'tx', 'sg', 'tso', 'ufo', 'gso' ]
+
+ PIF_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
+ 'management': (bool_to_xml,bool_from_xml),
+ 'network': (str_to_xml,str_from_xml),
+ 'device': (str_to_xml,str_from_xml),
+ 'bond_master_of': (lambda x, p, t, v: strlist_to_xml(x, p, 'bond_master_of', 'slave', v),
+ lambda n: strlist_from_xml(n, 'bond_master_of', 'slave')),
+ 'bond_slave_of': (str_to_xml,str_from_xml),
+ 'VLAN': (str_to_xml,str_from_xml),
+ 'VLAN_master_of': (str_to_xml,str_from_xml),
+ 'VLAN_slave_of': (lambda x, p, t, v: strlist_to_xml(x, p, 'VLAN_slave_of', 'master', v),
+ lambda n: strlist_from_xml(n, 'VLAN_slave_Of', 'master')),
+ 'ip_configuration_mode': (str_to_xml,str_from_xml),
+ 'IP': (str_to_xml,str_from_xml),
+ 'netmask': (str_to_xml,str_from_xml),
+ 'gateway': (str_to_xml,str_from_xml),
+ 'DNS': (str_to_xml,str_from_xml),
+ 'MAC': (str_to_xml,str_from_xml),
+ 'other_config': (lambda x, p, t, v: otherconfig_to_xml(x, p, v, PIF_OTHERCONFIG_ATTRS),
+ lambda n: otherconfig_from_xml(n, PIF_OTHERCONFIG_ATTRS)),
+ }
+
+ PIF_OTHERCONFIG_ATTRS = [ 'domain', 'peerdns', 'defaultroute', 'mtu', 'static-routes' ] + \
+ [ 'bond-%s' % x for x in 'mode', 'miimon', 'downdelay', 'updelay', 'use_carrier' ] + \
+ ETHTOOL_OTHERCONFIG_ATTRS
+
+ VLAN_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
+ 'tagged_PIF': (str_to_xml,str_from_xml),
+ 'untagged_PIF': (str_to_xml,str_from_xml),
+ }
+
+ BOND_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
+ 'master': (str_to_xml,str_from_xml),
+ 'slaves': (lambda x, p, t, v: strlist_to_xml(x, p, 'slaves', 'slave', v),
+ lambda n: strlist_from_xml(n, 'slaves', 'slave')),
+ }
+
+ NETWORK_ATTRS = { 'uuid': (str_to_xml,str_from_xml),
+ 'bridge': (str_to_xml,str_from_xml),
+ 'PIFs': (lambda x, p, t, v: strlist_to_xml(x, p, 'PIFs', 'PIF', v),
+ lambda n: strlist_from_xml(n, 'PIFs', 'PIF')),
+ 'other_config': (lambda x, p, t, v: otherconfig_to_xml(x, p, v, NETWORK_OTHERCONFIG_ATTRS),
+ lambda n: otherconfig_from_xml(n, NETWORK_OTHERCONFIG_ATTRS)),
+ }
+
+ NETWORK_OTHERCONFIG_ATTRS = [ 'mtu', 'static-routes' ] + ETHTOOL_OTHERCONFIG_ATTRS
+
class DatabaseCache(object):
+ def __read_xensource_inventory(self):
+ filename = "/etc/xensource-inventory"
+ f = open(filename, "r")
+ lines = [x.strip("\n") for x in f.readlines()]
+ f.close()
+
+ defs = [ (l[:l.find("=")], l[(l.find("=") + 1):]) for l in lines ]
+ defs = [ (a, b.strip("'")) for (a,b) in defs ]
+
+ return dict(defs)
+ def __pif_on_host(self,pif):
+ return self.__pifs.has_key(pif)
+
+ def __get_pif_records_from_xapi(self, session, host):
+ self.__pifs = {}
+ for (p,rec) in session.xenapi.PIF.get_all_records().items():
+ if rec['host'] != host:
+ continue
+ self.__pifs[p] = {}
+ for f in PIF_ATTRS:
+ self.__pifs[p][f] = rec[f]
+ self.__pifs[p]['other_config'] = {}
+ for f in PIF_OTHERCONFIG_ATTRS:
+ if not rec['other_config'].has_key(f): continue
+ self.__pifs[p]['other_config'][f] = rec['other_config'][f]
+
+ def __get_vlan_records_from_xapi(self, session):
+ self.__vlans = {}
+ for v in session.xenapi.VLAN.get_all():
+ rec = session.xenapi.VLAN.get_record(v)
+ if not self.__pif_on_host(rec['untagged_PIF']):
+ continue
+ self.__vlans[v] = {}
+ for f in VLAN_ATTRS:
+ self.__vlans[v][f] = rec[f]
+
+ def __get_bond_records_from_xapi(self, session):
+ self.__bonds = {}
+ for b in session.xenapi.Bond.get_all():
+ rec = session.xenapi.Bond.get_record(b)
+ if not self.__pif_on_host(rec['master']):
+ continue
+ self.__bonds[b] = {}
+ for f in BOND_ATTRS:
+ self.__bonds[b][f] = rec[f]
+
+ def __get_network_records_from_xapi(self, session):
+ self.__networks = {}
+ for n in session.xenapi.network.get_all():
+ rec = session.xenapi.network.get_record(n)
+ self.__networks[n] = {}
+ for f in NETWORK_ATTRS:
+ self.__networks[n][f] = rec[f]
+ self.__networks[n]['other_config'] = {}
+ for f in NETWORK_OTHERCONFIG_ATTRS:
+ if not rec['other_config'].has_key(f): continue
+ self.__networks[n]['other_config'][f] = rec['other_config'][f]
+
+ def __to_xml(self, xml, parent, key, ref, rec, attrs):
+ """Encode a database object as XML"""
+ e = xml.createElement(key)
+ parent.appendChild(e)
+ if ref:
+ e.setAttribute('ref', ref)
+
+ for n,v in rec.items():
+ if attrs.has_key(n):
+ h,_ = attrs[n]
+ h(xml, e, n, v)
+ else:
+ raise Error("Unknown attribute %s" % n)
+ def __from_xml(self, e, attrs):
+ """Decode a database object from XML"""
+ ref = e.attributes['ref'].value
+ rec = {}
+ for n in e.childNodes:
+ if n.nodeName in attrs:
+ _,h = attrs[n.nodeName]
+ rec[n.nodeName] = h(n)
+ return (ref,rec)
+
def __init__(self, session_ref=None, cache_file=None):
if session_ref and cache_file:
raise Error("can't specify session reference and cache file")
pifrec = db.get_pif_record(pif)
return bridge_name(pif)
-def physdev_names(pif):
- """Return the name(s) of the physical network device(s) associated with pif.
-For a VLAN PIF, the physical devices are the VLAN slave's physical devices.
-For a bond master PIF, the physical devices are the bond slaves.
-For a non-VLAN, non-bond master PIF, the physical device is the PIF itself.
+def get_physdev_pifs(pif):
+ """Return the PIFs for the physical network device(s) associated with pif.
+For a VLAN PIF, this is the VLAN slave's physical device PIF.
+For a bond master PIF, these are the bond slave PIFs.
+For a non-VLAN, non-bond master PIF, the PIF is its own physical device PIF.
"""
-
pifrec = db.get_pif_record(pif)
if pifrec['VLAN'] != '-1':