From: Ben Pfaff Date: Fri, 11 Feb 2011 21:16:28 +0000 (-0800) Subject: Remove /proc/net compatibility support. X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=0b8b6f71d5621a726a3bf5aa1bbee27ed1f4a8fe;p=openvswitch Remove /proc/net compatibility support. This feature was included only to allow Citrix QA to run some tests that interacted directly with the bridge. This feature hasn't been turned on for some time, so it should not be necessary any longer. Signed-off-by: Ben Pfaff --- diff --git a/datapath/brc_procfs.c b/datapath/brc_procfs.c deleted file mode 100644 index 36659482..00000000 --- a/datapath/brc_procfs.c +++ /dev/null @@ -1,186 +0,0 @@ -/* - * Copyright (c) 2009, 2010, 2011 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. - */ - -#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt - -#include -#include -#include -#include -#include -#include -#include "brc_procfs.h" -#include "openvswitch/brcompat-netlink.h" - -/* This code implements a Generic Netlink command BRC_GENL_C_SET_PROC that can - * be used to add, modify, and delete arbitrary files in selected - * subdirectories of /proc. It's a horrible kluge prompted by the need to - * simulate certain /proc/net/vlan and /proc/net/bonding files for software - * that wants to read them, and with any luck it will go away eventually. - * - * The implementation is a kluge too. In particular, we want to release the - * strings copied into the 'data' members of proc_dir_entry when the - * proc_dir_entry structures are freed, but there doesn't appear to be a way to - * hook that, so instead we have to rely on being the only entity modifying the - * directories in question. - */ - -static int brc_seq_show(struct seq_file *seq, void *unused) -{ - seq_puts(seq, seq->private); - return 0; -} - -static int brc_seq_open(struct inode *inode, struct file *file) -{ - return single_open(file, brc_seq_show, PDE(inode)->data); -} - -static struct file_operations brc_fops = { - .owner = THIS_MODULE, - .open = brc_seq_open, - .read = seq_read, - .llseek = seq_lseek, - .release = single_release, -}; - -static struct proc_dir_entry *proc_vlan_dir; -static struct proc_dir_entry *proc_bonding_dir; - -static struct proc_dir_entry *brc_lookup_entry(struct proc_dir_entry *de, const char *name) -{ - int namelen = strlen(name); - for (de = de->subdir; de; de = de->next) { - if (de->namelen != namelen) - continue; - if (!memcmp(name, de->name, de->namelen)) - return de; - } - return NULL; -} - -static struct proc_dir_entry *brc_open_dir(const char *dir_name, - struct proc_dir_entry *parent, - struct proc_dir_entry **dirp) -{ - if (!*dirp) { - struct proc_dir_entry *dir; - if (brc_lookup_entry(parent, dir_name)) { - pr_warn("%s proc directory exists, can't simulate--" - "probably its real module is loaded\n", - dir_name); - return NULL; - } - dir = *dirp = proc_mkdir(dir_name, parent); - } - return *dirp; -} - -int brc_genl_set_proc(struct sk_buff *skb, struct genl_info *info) -{ - struct proc_dir_entry *dir, *entry; - const char *dir_name, *name; - char *data; - - if (!info->attrs[BRC_GENL_A_PROC_DIR] || - VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DIR], BRC_NAME_LEN_MAX) || - !info->attrs[BRC_GENL_A_PROC_NAME] || - VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_NAME], BRC_NAME_LEN_MAX) || - (info->attrs[BRC_GENL_A_PROC_DATA] && - VERIFY_NUL_STRING(info->attrs[BRC_GENL_A_PROC_DATA], INT_MAX))) - return -EINVAL; - - dir_name = nla_data(info->attrs[BRC_GENL_A_PROC_DIR]); - name = nla_data(info->attrs[BRC_GENL_A_PROC_NAME]); - - if (!strcmp(dir_name, "net/vlan")) - dir = brc_open_dir("vlan", proc_net, &proc_vlan_dir); - else if (!strcmp(dir_name, "net/bonding")) - dir = brc_open_dir("bonding", proc_net, &proc_bonding_dir); - else - return -EINVAL; - if (!dir) { - /* Probably failed because the module that really implements - * the function in question is loaded and already owns the - * directory in question.*/ - return -EBUSY; - } - - entry = brc_lookup_entry(dir, name); - if (!info->attrs[BRC_GENL_A_PROC_DATA]) { - if (!entry) - return -ENOENT; - - data = entry->data; - remove_proc_entry(name, dir); - if (brc_lookup_entry(dir, name)) - return -EBUSY; /* Shouldn't happen */ - - kfree(data); - } else { - data = kstrdup(nla_data(info->attrs[BRC_GENL_A_PROC_DATA]), - GFP_KERNEL); - if (!data) - return -ENOMEM; - - if (entry) { - char *old_data = entry->data; - entry->data = data; - kfree(old_data); - return 0; - } - - entry = create_proc_entry(name, S_IFREG|S_IRUSR|S_IWUSR, dir); - if (!entry) { - kfree(data); - return -ENOBUFS; - } - entry->proc_fops = &brc_fops; - entry->data = data; - } - return 0; -} - -static void kill_proc_dir(const char *dir_name, - struct proc_dir_entry *parent, - struct proc_dir_entry *dir) -{ - if (!dir) - return; - for (;;) { - struct proc_dir_entry *e; - char *data; - char name[BRC_NAME_LEN_MAX + 1]; - - e = dir->subdir; - if (!e) - break; - - if (e->namelen >= sizeof(name)) { - /* Can't happen: we prevent adding names this long by - * limiting the BRC_GENL_A_PROC_NAME string to - * BRC_NAME_LEN_MAX bytes. */ - WARN_ON(1); - break; - } - strcpy(name, e->name); - - data = e->data; - e->data = NULL; - kfree(data); - - remove_proc_entry(name, dir); - } - remove_proc_entry(dir_name, parent); -} - -void brc_procfs_exit(void) -{ - kill_proc_dir("vlan", proc_net, proc_vlan_dir); - kill_proc_dir("bonding", proc_net, proc_bonding_dir); -} diff --git a/datapath/brc_procfs.h b/datapath/brc_procfs.h deleted file mode 100644 index 05afe409..00000000 --- a/datapath/brc_procfs.h +++ /dev/null @@ -1,22 +0,0 @@ -/* - * Copyright (c) 2009, 2011 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 BRC_PROCFS_H -#define BRC_PROCFS_H 1 - -struct sk_buff; -struct genl_info; - -/* Maximum length of BRC_GENL_A_PROC_DIR and BRC_GENL_A_PROC_NAME strings. */ -#define BRC_NAME_LEN_MAX 32 - -void brc_procfs_exit(void); -int brc_genl_set_proc(struct sk_buff *skb, struct genl_info *info); - -#endif /* brc_procfs.h */ - diff --git a/datapath/brcompat.c b/datapath/brcompat.c index 3e91dc5d..f9d00839 100644 --- a/datapath/brcompat.c +++ b/datapath/brcompat.c @@ -18,7 +18,6 @@ #include #include "openvswitch/brcompat-netlink.h" -#include "brc_procfs.h" #include "datapath.h" static struct genl_family brc_genl_family; @@ -399,15 +398,6 @@ nla_put_failure: /* Attribute policy: what each attribute may contain. */ static struct nla_policy brc_genl_policy[BRC_GENL_A_MAX + 1] = { [BRC_GENL_A_ERR_CODE] = { .type = NLA_U32 }, - -#ifdef HAVE_NLA_NUL_STRING - [BRC_GENL_A_PROC_DIR] = { .type = NLA_NUL_STRING, - .len = BRC_NAME_LEN_MAX }, - [BRC_GENL_A_PROC_NAME] = { .type = NLA_NUL_STRING, - .len = BRC_NAME_LEN_MAX }, - [BRC_GENL_A_PROC_DATA] = { .type = NLA_NUL_STRING }, -#endif - [BRC_GENL_A_FDB_DATA] = { .type = NLA_UNSPEC }, }; @@ -452,11 +442,6 @@ static struct genl_ops brc_genl_ops[] = { .policy = brc_genl_policy, .doit = brc_genl_dp_result, }, - { .cmd = BRC_GENL_C_SET_PROC, - .flags = GENL_ADMIN_PERM, /* Requires CAP_NET_ADMIN privelege. */ - .policy = brc_genl_policy, - .doit = brc_genl_set_proc, - }, }; static struct sk_buff *brc_send_command(struct sk_buff *request, @@ -555,7 +540,6 @@ static void brc_cleanup(void) brioctl_set(NULL); genl_unregister_family(&brc_genl_family); - brc_procfs_exit(); } module_init(brc_init); diff --git a/datapath/linux-2.6/.gitignore b/datapath/linux-2.6/.gitignore index ed7250f5..f5edd503 100644 --- a/datapath/linux-2.6/.gitignore +++ b/datapath/linux-2.6/.gitignore @@ -4,7 +4,6 @@ /Module.markers /actions.c /addrconf_core-openvswitch.c -/brc_procfs.c /brc_sysfs_dp.c /brc_sysfs_if.c /brcompat.c diff --git a/datapath/linux-2.6/Modules.mk b/datapath/linux-2.6/Modules.mk index 88c5769d..3fb9e9ba 100644 --- a/datapath/linux-2.6/Modules.mk +++ b/datapath/linux-2.6/Modules.mk @@ -58,9 +58,5 @@ openvswitch_headers += \ linux-2.6/compat-2.6/genetlink.inc both_modules += brcompat -brcompat_sources = \ - linux-2.6/compat-2.6/genetlink-brcompat.c \ - brcompat.c \ - brc_procfs.c -brcompat_headers = \ - brc_procfs.h +brcompat_sources = linux-2.6/compat-2.6/genetlink-brcompat.c brcompat.c +brcompat_headers = diff --git a/include/openvswitch/brcompat-netlink.h b/include/openvswitch/brcompat-netlink.h index 7d5ac4cf..d238a16f 100644 --- a/include/openvswitch/brcompat-netlink.h +++ b/include/openvswitch/brcompat-netlink.h @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, 2009 Nicira Networks. + * Copyright (c) 2008, 2009, 2011 Nicira Networks. * * This file is offered under your choice of two licenses: Apache 2.0 or GNU * GPL 2.0 or later. The permission statements for each of these licenses is @@ -64,11 +64,6 @@ enum { /* BRC_GENL_C_QUERY_MC. */ BRC_GENL_A_MC_GROUP, /* K: Generic netlink multicast group. */ - /* BRC_GENL_C_SET_PROC. */ - BRC_GENL_A_PROC_DIR, /* U: Name of subdirectory in /proc. */ - BRC_GENL_A_PROC_NAME, /* U: Name of file in /proc. */ - BRC_GENL_A_PROC_DATA, /* U: Contents of file in /proc. */ - /* BRC_GENL_C_FDB_QUERY. */ BRC_GENL_A_FDB_COUNT, /* K: Number of FDB entries to read. */ BRC_GENL_A_FDB_SKIP, /* K: Record offset into FDB to start reading. */ @@ -95,7 +90,6 @@ enum brc_genl_command { BRC_GENL_C_PORT_ADD, /* K: Port added to datapath. */ BRC_GENL_C_PORT_DEL, /* K: Port removed from datapath. */ BRC_GENL_C_QUERY_MC, /* U: Get multicast group for brcompat. */ - BRC_GENL_C_SET_PROC, /* U: Set contents of file in /proc. */ BRC_GENL_C_FDB_QUERY, /* K: Read records from forwarding database. */ BRC_GENL_C_GET_BRIDGES, /* K: Get ifindexes of all bridges. */ BRC_GENL_C_GET_PORTS, /* K: Get ifindexes of all ports on a bridge. */ diff --git a/vswitchd/automake.mk b/vswitchd/automake.mk index 0a2c7ff7..b8ee5b3b 100644 --- a/vswitchd/automake.mk +++ b/vswitchd/automake.mk @@ -9,8 +9,6 @@ DISTCLEANFILES += \ vswitchd_ovs_vswitchd_SOURCES = \ vswitchd/bridge.c \ vswitchd/bridge.h \ - vswitchd/proc-net-compat.c \ - vswitchd/proc-net-compat.h \ vswitchd/ovs-vswitchd.c \ vswitchd/system-stats.c \ vswitchd/system-stats.h \ diff --git a/vswitchd/bridge.c b/vswitchd/bridge.c index e92dd620..197b6ed4 100644 --- a/vswitchd/bridge.c +++ b/vswitchd/bridge.c @@ -55,7 +55,6 @@ #include "ovsdb-data.h" #include "packets.h" #include "poll-loop.h" -#include "proc-net-compat.h" #include "process.h" #include "sha1.h" #include "shash.h" @@ -191,7 +190,6 @@ struct port { tag_type active_iface_tag; /* Tag for bcast flows. */ tag_type no_ifaces_tag; /* Tag for flows when all ifaces disabled. */ int updelay, downdelay; /* Delay before iface goes up/down, in ms. */ - bool bond_compat_is_stale; /* Need to call port_update_bond_compat()? */ bool bond_fake_iface; /* Fake a bond interface for legacy compat? */ bool miimon; /* Use miimon instead of carrier? */ long long int bond_miimon_interval; /* Miimon status refresh interval. */ @@ -303,8 +301,6 @@ static struct port *port_lookup(const struct bridge *, const char *name); static struct iface *port_lookup_iface(const struct port *, const char *name); static struct port *port_from_dp_ifidx(const struct bridge *, uint16_t dp_ifidx); -static void port_update_bond_compat(struct port *); -static void port_update_vlan_compat(struct port *); static void port_update_bonding(struct port *); static void port_update_lacp(struct port *); @@ -915,7 +911,6 @@ bridge_reconfigure(const struct ovsrec_open_vswitch *ovs_cfg) struct port *port = br->ports[i]; int j; - port_update_vlan_compat(port); port_update_bonding(port); port_update_lacp(port); @@ -2210,7 +2205,6 @@ choose_output_iface(const struct port *port, const struct flow *flow, return false; } e->iface_tag = tag_create_random(); - ((struct port *) port)->bond_compat_is_stale = true; } *tags |= e->iface_tag; iface = port->ifaces[e->iface_idx]; @@ -2340,7 +2334,6 @@ bond_enable_slave(struct iface *iface, bool enable) } moving_active_iface = false; - port->bond_compat_is_stale = true; } /* Attempts to make the sum of the bond slaves' statistics appear on the fake @@ -2393,7 +2386,6 @@ bond_link_carrier_update(struct iface *iface, bool carrier) iface->up = carrier; iface->lacp_tx = 0; - iface->port->bond_compat_is_stale = true; } static void @@ -2452,11 +2444,6 @@ bond_run(struct bridge *br) port->bond_next_fake_iface_update = time_msec() + 1000; } } - - if (port->bond_compat_is_stale) { - port->bond_compat_is_stale = false; - port_update_bond_compat(port); - } } } @@ -3595,7 +3582,6 @@ bond_rebalance_port(struct port *port) } if (i < from->n_hashes) { bond_shift_load(from, to, i); - port->bond_compat_is_stale = true; /* If the result of the migration changed the relative order of * 'from' and 'to' swap them back to maintain invariants. */ @@ -4008,7 +3994,6 @@ bond_unixctl_migrate(struct unixctl_conn *conn, const char *args_, ofproto_revalidate(port->bridge->ofproto, entry->iface_tag); entry->iface_idx = iface->port_ifidx; entry->iface_tag = tag_create_random(); - port->bond_compat_is_stale = true; unixctl_command_reply(conn, 200, "migrated"); } @@ -4440,9 +4425,6 @@ port_destroy(struct port *port) struct port *del; int i; - proc_net_compat_update_vlan(port->name, NULL, 0); - proc_net_compat_update_bond(port->name, NULL); - for (i = 0; i < MAX_MIRRORS; i++) { struct mirror *m = br->mirrors[i]; if (m && m->out_port == port) { @@ -4545,12 +4527,8 @@ port_update_bonding(struct port *port) } if (port->n_ifaces < 2) { /* Not a bonded port. */ - if (port->bond_hash) { - free(port->bond_hash); - port->bond_hash = NULL; - port->bond_compat_is_stale = true; - } - + free(port->bond_hash); + port->bond_hash = NULL; port->bond_fake_iface = false; } else { size_t i; @@ -4574,7 +4552,6 @@ port_update_bonding(struct port *port) free(port->bond_hash); port->bond_hash = NULL; } - port->bond_compat_is_stale = true; port->bond_fake_iface = port->cfg->bond_fake_iface; if (!port->miimon) { @@ -4585,116 +4562,6 @@ port_update_bonding(struct port *port) } } } - -static void -port_update_bond_compat(struct port *port) -{ - struct compat_bond_hash compat_hashes[BOND_MASK + 1]; - struct compat_bond bond; - size_t i; - - if (port->n_ifaces < 2 || port->bond_mode != BM_SLB) { - proc_net_compat_update_bond(port->name, NULL); - return; - } - - bond.up = false; - bond.updelay = port->updelay; - bond.downdelay = port->downdelay; - - bond.n_hashes = 0; - bond.hashes = compat_hashes; - if (port->bond_hash) { - const struct bond_entry *e; - for (e = port->bond_hash; e <= &port->bond_hash[BOND_MASK]; e++) { - if (e->iface_idx >= 0 && e->iface_idx < port->n_ifaces) { - struct compat_bond_hash *cbh = &bond.hashes[bond.n_hashes++]; - cbh->hash = e - port->bond_hash; - cbh->netdev_name = port->ifaces[e->iface_idx]->name; - } - } - } - - bond.n_slaves = port->n_ifaces; - bond.slaves = xmalloc(port->n_ifaces * sizeof *bond.slaves); - for (i = 0; i < port->n_ifaces; i++) { - struct iface *iface = port->ifaces[i]; - struct compat_bond_slave *slave = &bond.slaves[i]; - slave->name = iface->name; - - /* We need to make the same determination as the Linux bonding - * code to determine whether a slave should be consider "up". - * The Linux function bond_miimon_inspect() supports four - * BOND_LINK_* states: - * - * - BOND_LINK_UP: carrier detected, updelay has passed. - * - BOND_LINK_FAIL: carrier lost, downdelay in progress. - * - BOND_LINK_DOWN: carrier lost, downdelay has passed. - * - BOND_LINK_BACK: carrier detected, updelay in progress. - * - * The function bond_info_show_slave() only considers BOND_LINK_UP - * to be "up" and anything else to be "down". - */ - slave->up = iface->enabled && iface->delay_expires == LLONG_MAX; - if (slave->up) { - bond.up = true; - } - netdev_get_etheraddr(iface->netdev, slave->mac); - } - - if (port->bond_fake_iface) { - struct netdev *bond_netdev; - - if (!netdev_open_default(port->name, &bond_netdev)) { - if (bond.up) { - netdev_turn_flags_on(bond_netdev, NETDEV_UP, true); - } else { - netdev_turn_flags_off(bond_netdev, NETDEV_UP, true); - } - netdev_close(bond_netdev); - } - } - - proc_net_compat_update_bond(port->name, &bond); - free(bond.slaves); -} - -static void -port_update_vlan_compat(struct port *port) -{ - struct bridge *br = port->bridge; - char *vlandev_name = NULL; - - if (port->vlan > 0) { - /* Figure out the name that the VLAN device should actually have, if it - * existed. This takes some work because the VLAN device would not - * have port->name in its name; rather, it would have the trunk port's - * name, and 'port' would be attached to a bridge that also had the - * VLAN device one of its ports. So we need to find a trunk port that - * includes port->vlan. - * - * There might be more than one candidate. This doesn't happen on - * XenServer, so if it happens we just pick the first choice in - * alphabetical order instead of creating multiple VLAN devices. */ - size_t i; - for (i = 0; i < br->n_ports; i++) { - struct port *p = br->ports[i]; - if (port_trunks_vlan(p, port->vlan) - && p->n_ifaces - && (!vlandev_name || strcmp(p->name, vlandev_name) <= 0)) - { - uint8_t ea[ETH_ADDR_LEN]; - netdev_get_etheraddr(p->ifaces[0]->netdev, ea); - if (!eth_addr_is_multicast(ea) && - !eth_addr_is_reserved(ea) && - !eth_addr_is_zero(ea)) { - vlandev_name = p->name; - } - } - } - } - proc_net_compat_update_vlan(port->name, vlandev_name, port->vlan); -} /* Interface functions. */ diff --git a/vswitchd/ovs-vswitchd.8.in b/vswitchd/ovs-vswitchd.8.in index 163ad205..f0badf0d 100644 --- a/vswitchd/ovs-vswitchd.8.in +++ b/vswitchd/ovs-vswitchd.8.in @@ -93,15 +93,6 @@ only allow privileged users, such as the superuser, to use it. \fBovs\-vswitchd\fR emits a log message if \fBmlockall()\fR is unavailable or unsuccessful. . -.IP "\fB\-\-fake\-proc\-net\fR" -Causes \fBovs\-vswitchd\fR to simulate some files in \fB/proc/net/vlan\fR -and \fB/proc/net/bonding\fR that some legacy software expects to -exist. This option should only be used if such legacy software is -actually in use. It requires the \fBbrcompat_mod.ko\fR kernel module -to be loaded. -.IP -On non-Linux hosts, this option is accepted but has no effect. -. .ds DD \ \fBovs\-vswitchd\fR detaches only after it has connected to the \ database, retrieved the initial configuration, and set up that \ diff --git a/vswitchd/ovs-vswitchd.c b/vswitchd/ovs-vswitchd.c index 2181e82e..1303e089 100644 --- a/vswitchd/ovs-vswitchd.c +++ b/vswitchd/ovs-vswitchd.c @@ -36,7 +36,6 @@ #include "netdev.h" #include "ovsdb-idl.h" #include "poll-loop.h" -#include "proc-net-compat.h" #include "process.h" #include "signals.h" #include "stream-ssl.h" @@ -117,7 +116,6 @@ parse_options(int argc, char *argv[]) enum { OPT_PEER_CA_CERT = UCHAR_MAX + 1, OPT_MLOCKALL, - OPT_FAKE_PROC_NET, VLOG_OPTION_ENUMS, LEAK_CHECKER_OPTION_ENUMS, OPT_BOOTSTRAP_CA_CERT, @@ -128,7 +126,6 @@ parse_options(int argc, char *argv[]) {"help", no_argument, 0, 'h'}, {"version", no_argument, 0, 'V'}, {"mlockall", no_argument, 0, OPT_MLOCKALL}, - {"fake-proc-net", no_argument, 0, OPT_FAKE_PROC_NET}, DAEMON_LONG_OPTIONS, VLOG_LONG_OPTIONS, LEAK_CHECKER_LONG_OPTIONS, @@ -141,7 +138,6 @@ parse_options(int argc, char *argv[]) {0, 0, 0, 0}, }; char *short_options = long_options_to_short_options(long_options); - int error; for (;;) { int c; @@ -170,14 +166,6 @@ parse_options(int argc, char *argv[]) #endif break; - case OPT_FAKE_PROC_NET: - error = proc_net_compat_init(); - if (error) { - ovs_fatal(error, "failed to initialize /proc/net " - "compatibility"); - } - break; - VLOG_OPTION_HANDLERS DAEMON_OPTION_HANDLERS LEAK_CHECKER_OPTION_HANDLERS @@ -228,9 +216,7 @@ usage(void) stream_usage("DATABASE", true, false, true); daemon_usage(); vlog_usage(); - printf("\nLegacy compatibility options:\n" - " --fake-proc-net simulate some files in /proc/net\n" - "\nOther options:\n" + printf("\nOther options:\n" " -h, --help display this help message\n" " -V, --version display version information\n"); leak_checker_usage(); diff --git a/vswitchd/proc-net-compat.c b/vswitchd/proc-net-compat.c deleted file mode 100644 index 3b7596ad..00000000 --- a/vswitchd/proc-net-compat.c +++ /dev/null @@ -1,371 +0,0 @@ -/* Copyright (c) 2009, 2010, 2011 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 -#include "proc-net-compat.h" - -#ifdef HAVE_NETLINK -#include -#include -#include -#include -#include -#include "dynamic-string.h" -#include "hash.h" -#include "netlink-protocol.h" -#include "netlink-socket.h" -#include "netlink.h" -#include "ofpbuf.h" -#include "openvswitch/brcompat-netlink.h" -#include "hmap.h" -#include "shash.h" -#include "svec.h" -#include "vlog.h" - -VLOG_DEFINE_THIS_MODULE(proc_net_compat); - -/* Netlink socket to bridge compatibility kernel module. */ -static struct nl_sock *brc_sock; - -/* The Generic Netlink family number used for bridge compatibility. */ -static int brc_family = 0; - -/* Rate limiting for log messages. */ -static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 5); - -static void flush_dir(const char *dir); -static int set_proc_file(const char *dir, const char *file, const char *data); - -/* Initializes the /proc/net compatibility layer. Returns 0 if successful, - * otherwise a positive errno value. */ -int -proc_net_compat_init(void) -{ - if (!brc_sock) { - int retval = nl_lookup_genl_family(BRC_GENL_FAMILY_NAME, &brc_family); - if (retval) { - return retval; - } - - retval = nl_sock_create(NETLINK_GENERIC, &brc_sock); - if (retval) { - return retval; - } - - flush_dir("/proc/net/vlan"); - flush_dir("/proc/net/bonding"); - } - return 0; -} - -static int -set_proc_file(const char *dir, const char *file, const char *data) -{ - struct ofpbuf request; - int retval; - - ofpbuf_init(&request, 0); - nl_msg_put_genlmsghdr(&request, 1024, brc_family, NLM_F_REQUEST, - BRC_GENL_C_SET_PROC, 1); - nl_msg_put_string(&request, BRC_GENL_A_PROC_DIR, dir); - nl_msg_put_string(&request, BRC_GENL_A_PROC_NAME, file); - if (data) { - nl_msg_put_string(&request, BRC_GENL_A_PROC_DATA, data); - } - - retval = nl_sock_transact(brc_sock, &request, NULL); - ofpbuf_uninit(&request); - if (retval) { - VLOG_WARN_RL(&rl, "failed to %s /proc/%s/%s (%s)", - data ? "update" : "remove", dir, file, strerror(retval)); - } - return retval; -} - -static void -flush_dir(const char *dir) -{ - const char *subdir; - struct dirent *de; - DIR *stream; - - assert(!memcmp(dir, "/proc/", 6)); - subdir = dir + 6; - - stream = opendir(dir); - if (!stream) { - if (errno != ENOENT) { - VLOG_WARN_RL(&rl, "%s: open failed (%s)", dir, strerror(errno)); - } - return; - } - - while ((de = readdir(stream)) != NULL) { - if (strcmp(de->d_name, ".") && strcmp(de->d_name, "..")) { - set_proc_file(subdir, de->d_name, NULL); - } - } - closedir(stream); -} - -/* If 'bond' is nonnull, creates a file in /proc/net/bonding for a bond with - * the given 'name' and the details in 'bond'. If 'bond' is null, deletes - * the /proc/net/bonding file with the given 'name'. - * - * This function has no effect unless proc_net_compat_init() has been - * called. */ -void -proc_net_compat_update_bond(const char *name, const struct compat_bond *bond) -{ - struct ds ds; - int i; - - if (!brc_sock) { - return; - } - - if (!bond) { - set_proc_file("net/bonding", name, NULL); - return; - } - - ds_init(&ds); - ds_put_format( - &ds, - "Ethernet Channel Bonding Driver: ovs-vswitchd " - VERSION BUILDNR" ("__DATE__" "__TIME__")\n" - "Bonding Mode: source load balancing\n" - "Primary Slave: None\n" - "Currently Active Slave: None\n" - "MII Status: %s\n" - "MII Polling Interval (ms): 100\n" - "Up Delay (ms): %d\n" - "Down Delay (ms): %d\n" - "\n" - "Source load balancing info:\n", - bond->up ? "up" : "down", bond->updelay, bond->downdelay); - - for (i = 0; i < bond->n_hashes; i++) { - const struct compat_bond_hash *cbh = &bond->hashes[i]; - ds_put_format(&ds, " [%03d] = %s\n", cbh->hash, cbh->netdev_name); - } - - for (i = 0; i < bond->n_slaves; i++) { - const struct compat_bond_slave *slave = &bond->slaves[i]; - ds_put_format( - &ds, - "\n" - "Slave Interface: %s\n" - "MII Status: %s\n" - "Link Failure Count: 0\n" - "Permanent HW addr: "ETH_ADDR_FMT"\n", - slave->name, slave->up ? "up" : "down", - ETH_ADDR_ARGS(slave->mac)); - } - set_proc_file("net/bonding", name, ds_cstr(&ds)); - ds_destroy(&ds); -} - -/* /proc/net/vlan compatibility. - * - * This is much more complex than I expected it to be. */ - -struct compat_vlan { - /* Hash key. */ - struct hmap_node trunk_node; /* Hash map node. */ - char *trunk_dev; /* Name of trunk network device. */ - int vid; /* VLAN number. */ - - /* Auxiliary data. */ - char *vlan_dev; /* sprintf("%s.%d", trunk_dev, vid); */ - struct svec tagged_devs; /* Name of tagged network device(s). */ -}; - -/* Current set of VLAN devices, indexed two different ways. */ -static struct hmap vlans_by_trunk = HMAP_INITIALIZER(&vlans_by_trunk); -static struct shash vlans_by_tagged = SHASH_INITIALIZER(&vlans_by_tagged); - -static bool remove_tagged_dev(struct shash_node *, const char *tagged_dev); -static void update_vlan_config(void); -static void set_vlan_proc_file(const struct compat_vlan *); -static uint32_t hash_vlan(const char *trunk_dev, uint32_t vid); - -/* Updates the /proc/net/vlan compatibility layer's idea of what trunk device - * and VLAN the given 'tagged_dev' is associated with. If 'tagged_dev' has an - * implicit VLAN tag, then 'trunk_dev' should be the name of a network device - * on the same bridge that trunks that VLAN, and 'vid' should be the VLAN tag - * number. If 'tagged_dev' does not have an implicit VLAN tag, then - * 'trunk_dev' should be NULL and 'vid' should be -1. - * - * This function has no effect unless proc_net_compat_init() has been - * called. */ -void -proc_net_compat_update_vlan(const char *tagged_dev, const char *trunk_dev, - int vid) -{ - struct compat_vlan *vlan; - struct shash_node *node; - - if (!brc_sock) { - return; - } - - /* Find the compat_vlan that we currently have for 'tagged_dev' (if - * any). */ - node = shash_find(&vlans_by_tagged, tagged_dev); - vlan = node ? node->data : NULL; - if (vid <= 0 || !trunk_dev) { - if (vlan) { - if (remove_tagged_dev(node, tagged_dev)) { - update_vlan_config(); - } - } - } else { - if (vlan) { - if (!strcmp(trunk_dev, vlan->trunk_dev) && vid == vlan->vid) { - /* No change. */ - return; - } else { - /* 'tagged_dev' is attached to the wrong compat_vlan. Start - * by removing it from that one. */ - remove_tagged_dev(node, tagged_dev); - node = NULL; - vlan = NULL; - } - } - - /* 'tagged_dev' is not attached to any compat_vlan. Find the - * compat_vlan corresponding to (trunk_dev,vid) to attach it to, or - * create a new compat_vlan if none exists for (trunk_dev,vid). */ - HMAP_FOR_EACH_WITH_HASH (vlan, trunk_node, hash_vlan(trunk_dev, vid), - &vlans_by_trunk) { - if (!strcmp(trunk_dev, vlan->trunk_dev) && vid == vlan->vid) { - break; - } - } - if (!vlan) { - /* Create a new compat_vlan for (trunk_dev,vid). */ - vlan = xzalloc(sizeof *vlan); - vlan->trunk_dev = xstrdup(trunk_dev); - vlan->vid = vid; - vlan->vlan_dev = xasprintf("%s.%d", trunk_dev, vid); - svec_init(&vlan->tagged_devs); - hmap_insert(&vlans_by_trunk, &vlan->trunk_node, - hash_vlan(trunk_dev, vid)); - set_vlan_proc_file(vlan); - } - - /* Attach 'tagged_dev' to 'vlan'. */ - svec_add(&vlan->tagged_devs, tagged_dev); - shash_add(&vlans_by_tagged, tagged_dev, vlan); - svec_sort(&vlan->tagged_devs); - update_vlan_config(); - } -} - -/* Remove 'tagged_dev' from the compat_vlan in 'node'. If that causes the - * compat_vlan to have no tagged_devs left, destroy the compat_vlan too. */ -static bool -remove_tagged_dev(struct shash_node *node, const char *tagged_dev) -{ - struct compat_vlan *vlan = node->data; - - svec_del(&vlan->tagged_devs, tagged_dev); - shash_delete(&vlans_by_tagged, node); - if (!vlan->tagged_devs.n) { - set_proc_file("net/vlan", vlan->vlan_dev, NULL); - - hmap_remove(&vlans_by_trunk, &vlan->trunk_node); - svec_destroy(&vlan->tagged_devs); - free(vlan->trunk_dev); - free(vlan->vlan_dev); - free(vlan); - return true; - } - return false; -} - -/* Returns a hash value for (trunk_dev,vid). */ -static uint32_t -hash_vlan(const char *trunk_dev, uint32_t vid) -{ - return hash_int(vid, hash_string(trunk_dev, 0)); -} - -/* Update /proc/net/vlan/ for 'vlan'. */ -static void -set_vlan_proc_file(const struct compat_vlan *vlan) -{ - struct ds ds; - - ds_init(&ds); - ds_put_format( - &ds, - "%s VID: %d\t REORDER_HDR: 1 dev->priv_flags: 81\n" - " total frames received 0\n" - " total bytes received 0\n" - " Broadcast/Multicast Rcvd 0\n" - "\n" - " total frames transmitted 0\n" - " total bytes transmitted 0\n" - " total headroom inc 0\n" - " total encap on xmit 0\n" - "Device: %s\n" - "INGRESS priority mappings: 0:0 1:0 2:0 3:0 4:0 5:0 6:0 7:0\n" - "EGRESSS priority Mappings: \n", - vlan->vlan_dev, vlan->vid, vlan->trunk_dev); - set_proc_file("net/vlan", vlan->vlan_dev, ds_cstr(&ds)); - ds_destroy(&ds); -} - -/* Update /proc/net/vlan/config. */ -static void -update_vlan_config(void) -{ - struct compat_vlan *vlan; - struct ds ds; - - ds_init(&ds); - ds_put_cstr(&ds, "VLAN Dev name | VLAN ID\n" - "Name-Type: VLAN_NAME_TYPE_RAW_PLUS_VID_NO_PAD\n"); - HMAP_FOR_EACH (vlan, trunk_node, &vlans_by_trunk) { - ds_put_format(&ds, "%-15s| %d | %s\n", - vlan->vlan_dev, vlan->vid, vlan->trunk_dev); - } - set_proc_file("net/vlan", "config", ds_cstr(&ds)); - ds_destroy(&ds); -} -#else /* !HAVE_NETLINK */ -#include "compiler.h" - -int -proc_net_compat_init(void) -{ - return 0; -} - -void -proc_net_compat_update_bond(const char *name OVS_UNUSED, - const struct compat_bond *bond OVS_UNUSED) -{ -} - -void -proc_net_compat_update_vlan(const char *tagged_dev OVS_UNUSED, - const char *trunk_dev OVS_UNUSED, - int vid OVS_UNUSED) -{ -} -#endif /* !HAVE_NETLINK */ diff --git a/vswitchd/proc-net-compat.h b/vswitchd/proc-net-compat.h deleted file mode 100644 index 82d550f5..00000000 --- a/vswitchd/proc-net-compat.h +++ /dev/null @@ -1,49 +0,0 @@ -/* 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. - */ - -#ifndef VSWITCHD_PROC_NET_COMPAT_H -#define VSWITCHD_PROC_NET_COMPAT_H 1 - -#include "packets.h" - -struct compat_bond { - bool up; - int updelay; - int downdelay; - - int n_hashes; - struct compat_bond_hash *hashes; - - int n_slaves; - struct compat_bond_slave *slaves; -}; - -struct compat_bond_hash { - int hash; - const char *netdev_name; -}; - -struct compat_bond_slave { - const char *name; - bool up; - uint8_t mac[ETH_ADDR_LEN]; -}; - -int proc_net_compat_init(void); -void proc_net_compat_update_bond(const char *name, const struct compat_bond *); -void proc_net_compat_update_vlan(const char *dev, const char *vlandev, - int vlan); - -#endif /* vswitchd/proc-net-compat.h */