-/* Copyright (c) 2008, 2009, 2010 Nicira Networks
+/* Copyright (c) 2008, 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.
#include "leak-checker.h"
#include "netdev.h"
#include "netlink.h"
+#include "netlink-socket.h"
#include "ofpbuf.h"
#include "openvswitch/brcompat-netlink.h"
#include "ovsdb-idl.h"
#include "poll-loop.h"
#include "process.h"
#include "signals.h"
-#include "svec.h"
+#include "sset.h"
#include "timeval.h"
#include "unixctl.h"
#include "util.h"
+#include "vlog.h"
#include "vswitchd/vswitch-idl.h"
-#include "vlog.h"
-#define THIS_MODULE VLM_brcompatd
+VLOG_DEFINE_THIS_MODULE(brcompatd);
/* xxx Just hangs if datapath is rmmod/insmod. Learn to reconnect? */
static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(5, 60);
-/* Maximum number of milliseconds to wait before pruning port entries that
+/* Maximum number of milliseconds to wait before pruning port entries that
* no longer exist. If set to zero, ports are never pruned. */
static int prune_timeout = 5000;
struct nlattr *attrs[ARRAY_SIZE(brc_multicast_policy)];
int retval;
- retval = nl_sock_create(NETLINK_GENERIC, 0, 0, 0, &sock);
+ retval = nl_sock_create(NETLINK_GENERIC, &sock);
if (retval) {
return retval;
}
ofpbuf_init(&request, 0);
- nl_msg_put_genlmsghdr(&request, sock, 0, brc_family,
+ nl_msg_put_genlmsghdr(&request, 0, brc_family,
NLM_F_REQUEST, BRC_GENL_C_QUERY_MC, 1);
retval = nl_sock_transact(sock, &request, &reply);
ofpbuf_uninit(&request);
return retval;
}
- retval = nl_sock_create(NETLINK_GENERIC, multicast_group, 0, 0, sock);
+ retval = nl_sock_create(NETLINK_GENERIC, sock);
if (retval) {
return retval;
}
- return 0;
+ retval = nl_sock_join_mcgroup(*sock, multicast_group);
+ if (retval) {
+ nl_sock_destroy(*sock);
+ *sock = NULL;
+ }
+ return retval;
}
static const struct nl_policy brc_dp_policy[] = {
}
static void
-do_get_bridge_parts(const struct ovsrec_bridge *br, struct svec *parts,
+do_get_bridge_parts(const struct ovsrec_bridge *br, struct sset *parts,
int vlan, bool break_down_bonds)
{
- struct svec ports;
size_t i, j;
- svec_init(&ports);
for (i = 0; i < br->n_ports; i++) {
const struct ovsrec_port *port = br->ports[i];
- svec_add(&ports, port->name);
if (vlan >= 0) {
int port_vlan = port->n_tag ? *port->tag : 0;
if (vlan != port_vlan) {
if (break_down_bonds) {
for (j = 0; j < port->n_interfaces; j++) {
const struct ovsrec_interface *iface = port->interfaces[j];
- svec_add(parts, iface->name);
+ sset_add(parts, iface->name);
}
} else {
- svec_add(parts, port->name);
+ sset_add(parts, port->name);
}
}
- svec_destroy(&ports);
}
/* Add all the interfaces for 'bridge' to 'ifaces', breaking bonded interfaces
* reported. If 'vlan' > 0, only interfaces with implicit VLAN 'vlan' are
* reported. */
static void
-get_bridge_ifaces(const struct ovsrec_bridge *br, struct svec *ifaces,
+get_bridge_ifaces(const struct ovsrec_bridge *br, struct sset *ifaces,
int vlan)
{
do_get_bridge_parts(br, ifaces, vlan, true);
* only trunk ports or ports with implicit VLAN 0 are reported. If 'vlan' > 0,
* only port with implicit VLAN 'vlan' are reported. */
static void
-get_bridge_ports(const struct ovsrec_bridge *br, struct svec *ports,
+get_bridge_ports(const struct ovsrec_bridge *br, struct sset *ports,
int vlan)
{
do_get_bridge_parts(br, ports, vlan, false);
}
-#if 0
-/* Go through the configuration file and remove any ports that no longer
- * exist associated with a bridge. */
-static void
-prune_ports(void)
-{
- int i, j;
- struct svec bridges, delete;
-
- if (cfg_lock(NULL, 0)) {
- /* Couldn't lock config file. */
- return;
- }
-
- svec_init(&bridges);
- svec_init(&delete);
- cfg_get_subsections(&bridges, "bridge");
- for (i=0; i<bridges.n; i++) {
- const char *br_name = bridges.names[i];
- struct svec ifaces;
-
- /* Check that each bridge interface exists. */
- svec_init(&ifaces);
- get_bridge_ifaces(br_name, &ifaces, -1);
- for (j = 0; j < ifaces.n; j++) {
- const char *iface_name = ifaces.names[j];
-
- /* The local port and internal ports are created and destroyed by
- * ovs-vswitchd itself, so don't bother checking for them at all.
- * In practice, they might not exist if ovs-vswitchd hasn't
- * finished reloading since the configuration file was updated. */
- if (!strcmp(iface_name, br_name)
- || cfg_get_bool(0, "iface.%s.internal", iface_name)) {
- continue;
- }
-
- if (!netdev_exists(iface_name)) {
- VLOG_INFO_RL(&rl, "removing dead interface %s from %s",
- iface_name, br_name);
- svec_add(&delete, iface_name);
- }
- }
- svec_destroy(&ifaces);
- }
- svec_destroy(&bridges);
-
- if (delete.n) {
- size_t i;
-
- for (i = 0; i < delete.n; i++) {
- cfg_del_match("bridge.*.port=%s", delete.names[i]);
- cfg_del_match("bonding.*.slave=%s", delete.names[i]);
- }
- reload_config();
- cfg_unlock();
- } else {
- cfg_unlock();
- }
- svec_destroy(&delete);
-}
-#endif
-
static struct ovsdb_idl_txn *
txn_from_openvswitch(const struct ovsrec_open_vswitch *ovs)
{
struct ovsrec_bridge *bridge)
{
struct ovsrec_bridge **bridges;
- size_t i;
+ size_t i;
bridges = xmalloc(sizeof *ovs->bridges * (ovs->n_bridges + 1));
for (i = 0; i < ovs->n_bridges; i++) {
bridges[ovs->n_bridges] = bridge;
ovsrec_open_vswitch_set_bridges(ovs, bridges, ovs->n_bridges + 1);
free(bridges);
-}
+}
static struct json *
where_uuid_equals(const struct uuid *uuid)
port = ovsrec_port_insert(txn_from_openvswitch(ovs));
ovsrec_port_set_name(port, br_name);
ovsrec_port_set_interfaces(port, &iface, 1);
-
+
br = ovsrec_bridge_insert(txn_from_openvswitch(ovs));
ovsrec_bridge_set_name(br, br_name);
ovsrec_bridge_set_ports(br, &port, 1);
-
+
ovs_insert_bridge(ovs, br);
return commit_txn(txn, true);
}
static void
-add_port(const struct ovsrec_open_vswitch *ovs,
+add_port(const struct ovsrec_open_vswitch *ovs,
const struct ovsrec_bridge *br, const char *port_name)
{
struct ovsrec_interface *iface;
}
ovsrec_bridge_set_ports(br, ports, n);
free(ports);
-
- /* Delete all of the port's interfaces. */
- for (i = 0; i < port->n_interfaces; i++) {
- ovsrec_interface_delete(port->interfaces[i]);
- }
-
- /* Delete the port itself. */
- ovsrec_port_delete(port);
}
/* Delete 'iface' from 'port' (which must be within 'br'). If 'iface' was
}
ovsrec_port_set_interfaces(port, ifaces, n);
free(ifaces);
- ovsrec_interface_delete(iface);
}
}
ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: delbr %s", br_name);
- /* Delete everything that the bridge points to, then delete the bridge
- * itself. */
- while (br->n_ports > 0) {
- del_port(br, br->ports[0]);
- }
- for (i = 0; i < br->n_mirrors; i++) {
- ovsrec_mirror_delete(br->mirrors[i]);
- }
- if (br->netflow) {
- ovsrec_netflow_delete(br->netflow);
- }
- if (br->sflow) {
- ovsrec_sflow_delete(br->sflow);
- }
- if (br->controller) {
- ovsrec_controller_delete(br->controller);
- }
-
/* Remove 'br' from the vswitch's list of bridges. */
bridges = xmalloc(sizeof *ovs->bridges * ovs->n_bridges);
for (i = n = 0; i < ovs->n_bridges; i++) {
ovsrec_open_vswitch_set_bridges(ovs, bridges, n);
free(bridges);
- /* Delete the bridge itself. */
- ovsrec_bridge_delete(br);
-
return commit_txn(txn, true);
}
compose_reply(uint32_t seq, int error)
{
struct ofpbuf *reply = ofpbuf_new(4096);
- nl_msg_put_genlmsghdr(reply, brc_sock, 32, brc_family, NLM_F_REQUEST,
+ nl_msg_put_genlmsghdr(reply, 32, brc_family, NLM_F_REQUEST,
BRC_GENL_C_DP_RESULT, 1);
((struct nlmsghdr *) reply->data)->nlmsg_seq = seq;
nl_msg_put_u32(reply, BRC_GENL_A_ERR_CODE, error);
static int
handle_bridge_cmd(struct ovsdb_idl *idl,
- const struct ovsrec_open_vswitch *ovs,
+ const struct ovsrec_open_vswitch *ovs,
struct ofpbuf *buffer, bool add)
{
const char *br_name;
const char *linux_name; /* Name used by brctl. */
const struct ovsrec_bridge *ovs_bridge; /* Bridge used by ovs-vswitchd. */
int br_vlan; /* VLAN tag. */
- struct svec ifaces;
+ struct sset ifaces;
struct ofpbuf query_data;
+ const char *iface_name;
struct ofpbuf *reply;
char *unixctl_command;
uint64_t count, skip;
}
/* Figure out vswitchd bridge and VLAN. */
- error = linux_bridge_to_ovs_bridge(ovs, linux_name,
+ error = linux_bridge_to_ovs_bridge(ovs, linux_name,
&ovs_bridge, &br_vlan);
if (error) {
send_simple_reply(seq, error);
/* Fetch the MAC address for each interface on the bridge, so that we can
* fill in the is_local field in the response. */
- svec_init(&ifaces);
+ sset_init(&ifaces);
get_bridge_ifaces(ovs_bridge, &ifaces, br_vlan);
- local_macs = xmalloc(ifaces.n * sizeof *local_macs);
+ local_macs = xmalloc(sset_count(&ifaces) * sizeof *local_macs);
n_local_macs = 0;
- for (i = 0; i < ifaces.n; i++) {
- const char *iface_name = ifaces.names[i];
+ SSET_FOR_EACH (iface_name, &ifaces) {
struct mac *mac = &local_macs[n_local_macs];
struct netdev *netdev;
netdev_close(netdev);
}
}
- svec_destroy(&ifaces);
+ sset_destroy(&ifaces);
/* Parse the response from ovs-appctl and convert it to binary format to
* pass back to the kernel. */
if (sscanf(line, "%d %d "ETH_ADDR_SCAN_FMT" %d",
&port, &vlan, ETH_ADDR_SCAN_ARGS(mac), &age)
!= 2 + ETH_ADDR_SCAN_COUNT + 1) {
- struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
+ static struct vlog_rate_limit rl = VLOG_RATE_LIMIT_INIT(1, 1);
VLOG_INFO_RL(&rl, "fdb/show output has invalid format: %s", line);
continue;
}
/* Free memory. */
ofpbuf_uninit(&query_data);
+ free(local_macs);
return 0;
}
static void
-send_ifindex_reply(uint32_t seq, struct svec *ifaces)
+send_ifindex_reply(uint32_t seq, struct sset *ifaces)
{
struct ofpbuf *reply;
const char *iface;
size_t n_indices;
int *indices;
- size_t i;
-
- /* Make sure that any given interface only occurs once. This shouldn't
- * happen, but who knows what people put into their configuration files. */
- svec_sort_unique(ifaces);
/* Convert 'ifaces' into ifindexes. */
n_indices = 0;
- indices = xmalloc(ifaces->n * sizeof *indices);
- SVEC_FOR_EACH (i, iface, ifaces) {
+ indices = xmalloc(sset_count(ifaces) * sizeof *indices);
+ SSET_FOR_EACH (iface, ifaces) {
int ifindex = if_nametoindex(iface);
if (ifindex) {
indices[n_indices++] = ifindex;
handle_get_bridges_cmd(const struct ovsrec_open_vswitch *ovs,
struct ofpbuf *buffer)
{
- struct svec bridges;
+ struct sset bridges;
size_t i, j;
uint32_t seq;
}
/* Get all the real bridges and all the fake ones. */
- svec_init(&bridges);
+ sset_init(&bridges);
for (i = 0; i < ovs->n_bridges; i++) {
const struct ovsrec_bridge *br = ovs->bridges[i];
- svec_add(&bridges, br->name);
+ sset_add(&bridges, br->name);
for (j = 0; j < br->n_ports; j++) {
const struct ovsrec_port *port = br->ports[j];
if (port->fake_bridge) {
- svec_add(&bridges, port->name);
+ sset_add(&bridges, port->name);
}
}
}
send_ifindex_reply(seq, &bridges);
- svec_destroy(&bridges);
+ sset_destroy(&bridges);
return 0;
}
const struct ovsrec_bridge *ovs_bridge;
int br_vlan;
- struct svec ports;
+ struct sset ports;
int error;
return error;
}
- error = linux_bridge_to_ovs_bridge(ovs, linux_name,
+ error = linux_bridge_to_ovs_bridge(ovs, linux_name,
&ovs_bridge, &br_vlan);
if (error) {
send_simple_reply(seq, error);
return error;
}
- svec_init(&ports);
+ sset_init(&ports);
get_bridge_ports(ovs_bridge, &ports, br_vlan);
- svec_sort(&ports);
- svec_del(&ports, linux_name);
+ sset_find_and_delete(&ports, linux_name);
send_ifindex_reply(seq, &ports); /* XXX bonds won't show up */
- svec_destroy(&ports);
+ sset_destroy(&ports);
return 0;
}
+static struct ofpbuf *
+brc_recv_update__(void)
+{
+ for (;;) {
+ struct ofpbuf *buffer;
+ int retval;
+
+ retval = nl_sock_recv(brc_sock, &buffer, false);
+ switch (retval) {
+ case 0:
+ if (nl_msg_nlmsgerr(buffer, NULL)
+ || nl_msg_nlmsghdr(buffer)->nlmsg_type == NLMSG_DONE) {
+ break;
+ }
+ return buffer;
+
+ case ENOBUFS:
+ break;
+
+ case EAGAIN:
+ return NULL;
+
+ default:
+ VLOG_WARN_RL(&rl, "brc_recv_update: %s", strerror(retval));
+ return NULL;
+ }
+ ofpbuf_delete(buffer);
+ }
+}
+
static void
brc_recv_update(struct ovsdb_idl *idl)
{
- int retval;
struct ofpbuf *buffer;
struct genlmsghdr *genlmsghdr;
const struct ovsrec_open_vswitch *ovs;
- buffer = NULL;
- do {
- ofpbuf_delete(buffer);
- retval = nl_sock_recv(brc_sock, &buffer, false);
- } while (retval == ENOBUFS
- || (!retval
- && (nl_msg_nlmsgerr(buffer, NULL)
- || nl_msg_nlmsghdr(buffer)->nlmsg_type == NLMSG_DONE)));
- if (retval) {
- if (retval != EAGAIN) {
- VLOG_WARN_RL(&rl, "brc_recv_update: %s", strerror(retval));
- }
+ buffer = brc_recv_update__();
+ if (!buffer) {
return;
}
} else if (error == ENOBUFS) {
VLOG_WARN_RL(&rl, "network monitor socket overflowed");
} else if (error) {
- VLOG_WARN_RL(&rl, "error on network monitor socket: %s",
+ VLOG_WARN_RL(&rl, "error on network monitor socket: %s",
strerror(error));
} else {
struct nlattr *attrs[ARRAY_SIZE(rtnlgrp_link_policy)];
VLOG_WARN_RL(&rl, "received bad rtnl message (no ifinfomsg)");
ofpbuf_delete(buf);
return;
- }
-
+ }
+
if (!nl_policy_parse(buf, NLMSG_HDRLEN + sizeof(struct ifinfomsg),
rtnlgrp_link_policy,
attrs, ARRAY_SIZE(rtnlgrp_link_policy))) {
br = find_bridge(ovs, br_name);
if (!br) {
- VLOG_WARN("no bridge named %s from which to remove %s",
+ VLOG_WARN("no bridge named %s from which to remove %s",
br_name, port_name);
ofpbuf_delete(buf);
return;
int
main(int argc, char *argv[])
{
+ extern struct vlog_module VLM_reconnect;
struct unixctl_server *unixctl;
const char *remote;
struct ovsdb_idl *idl;
proctitle_init(argc, argv);
set_program_name(argv[0]);
- time_init();
- vlog_init();
- vlog_set_levels(VLM_ANY_MODULE, VLF_CONSOLE, VLL_WARN);
- vlog_set_levels(VLM_reconnect, VLF_ANY_FACILITY, VLL_WARN);
+ vlog_set_levels(NULL, VLF_CONSOLE, VLL_WARN);
+ vlog_set_levels(&VLM_reconnect, VLF_ANY_FACILITY, VLL_WARN);
remote = parse_options(argc, argv);
signal(SIGPIPE, SIG_IGN);
process_init();
ovsrec_init();
- die_if_already_running();
daemonize_start();
retval = unixctl_server_create(NULL, &unixctl);
}
if (brc_open(&brc_sock)) {
- ovs_fatal(0, "could not open brcompat socket. Check "
- "\"brcompat\" kernel module.");
+ VLOG_FATAL("could not open brcompat socket. Check "
+ "\"brcompat\" kernel module.");
}
if (prune_timeout) {
- if (nl_sock_create(NETLINK_ROUTE, RTNLGRP_LINK, 0, 0, &rtnl_sock)) {
- ovs_fatal(0, "could not create rtnetlink socket");
+ int error;
+
+ error = nl_sock_create(NETLINK_ROUTE, &rtnl_sock);
+ if (error) {
+ VLOG_FATAL("could not create rtnetlink socket (%s)",
+ strerror(error));
+ }
+
+ error = nl_sock_join_mcgroup(rtnl_sock, RTNLGRP_LINK);
+ if (error) {
+ VLOG_FATAL("could not join RTNLGRP_LINK multicast group (%s)",
+ strerror(error));
}
}
daemonize_complete();
- idl = ovsdb_idl_create(remote, &ovsrec_idl_class);
+ idl = ovsdb_idl_create(remote, &ovsrec_idl_class, true);
for (;;) {
const struct ovsrec_open_vswitch *ovs;
netdev_run();
/* If 'prune_timeout' is non-zero, we actively prune from the
- * configuration of port entries that are no longer valid. We
- * use two methods:
+ * configuration of port entries that are no longer valid. We
+ * use two methods:
*
* 1) The kernel explicitly notifies us of removed ports
* through the RTNL messages.
*/
if (ovs && prune_timeout) {
rtnl_recv_update(idl, ovs);
-#if 0
- prune_ports();
-#endif
-
nl_sock_wait(rtnl_sock, POLLIN);
poll_timer_wait(prune_timeout);
}
} else if (p[1] == 's') {
n++;
} else {
- ovs_fatal(0, "only '%%s' and '%%%%' allowed in --appctl-command");
+ VLOG_FATAL("only '%%s' and '%%%%' allowed in --appctl-command");
}
}
if (n != 1) {
- ovs_fatal(0, "'%%s' must appear exactly once in --appctl-command");
+ VLOG_FATAL("'%%s' must appear exactly once in --appctl-command");
}
}
OPT_PRUNE_TIMEOUT,
OPT_APPCTL_COMMAND,
VLOG_OPTION_ENUMS,
- LEAK_CHECKER_OPTION_ENUMS
+ LEAK_CHECKER_OPTION_ENUMS,
+ DAEMON_OPTION_ENUMS
};
static struct option long_options[] = {
{"help", no_argument, 0, 'h'},
};
char *short_options = long_options_to_short_options(long_options);
- appctl_command = xasprintf("%s/ovs-appctl %%s", ovs_bindir);
+ appctl_command = xasprintf("%s/ovs-appctl %%s", ovs_bindir());
for (;;) {
int c;
argv += optind;
if (argc != 1) {
- ovs_fatal(0, "database socket is non-option argument; "
- "use --help for usage");
+ VLOG_FATAL("database socket is non-option argument; "
+ "use --help for usage");
}
return argv[0];