-static bool
-bridge_exists(const char *name)
-{
- return cfg_has_section("bridge.%s", name);
-}
-
-static int
-execute_appctl_command(const char *unixctl_command, char **output)
-{
- char *stdout_log, *stderr_log;
- int error, status;
- char *argv[5];
-
- argv[0] = "/bin/sh";
- argv[1] = "-c";
- argv[2] = xasprintf(appctl_command, unixctl_command);
- argv[3] = NULL;
-
- /* Run process and log status. */
- error = process_run_capture(argv, &stdout_log, &stderr_log, &status);
- if (error) {
- VLOG_ERR("failed to execute %s command via ovs-appctl: %s",
- unixctl_command, strerror(error));
- } else if (status) {
- char *msg = process_status_msg(status);
- VLOG_ERR("ovs-appctl exited with error (%s)", msg);
- free(msg);
- error = ECHILD;
- }
-
- /* Deal with stdout_log. */
- if (output) {
- *output = stdout_log;
- } else {
- free(stdout_log);
- }
-
- /* Deal with stderr_log */
- if (stderr_log && *stderr_log) {
- VLOG_INFO("ovs-appctl wrote to stderr:\n%s", stderr_log);
- }
- free(stderr_log);
-
- free(argv[2]);
-
- return error;
-}
-
-static int
-rewrite_and_reload_config(void)
-{
- if (cfg_is_dirty()) {
- int error1 = cfg_write();
- int error2 = cfg_read();
- long long int reload_start = time_msec();
- int error3 = execute_appctl_command("vswitchd/reload", NULL);
- long long int elapsed = time_msec() - reload_start;
- COVERAGE_INC(brcompatd_reload);
- if (elapsed > 0) {
- VLOG_INFO("reload command executed in %lld ms", elapsed);
- }
- return error1 ? error1 : error2 ? error2 : error3;
- }
- return 0;
-}
-
-static void
-do_get_bridge_parts(const char *bridge, struct svec *parts, int vlan,
- bool break_down_bonds)
-{
- struct svec ports;
- int i;
-
- svec_init(&ports);
- cfg_get_all_keys(&ports, "bridge.%s.port", bridge);
- for (i = 0; i < ports.n; i++) {
- const char *port_name = ports.names[i];
- if (vlan >= 0) {
- int port_vlan = cfg_get_vlan(0, "vlan.%s.tag", port_name);
- if (port_vlan < 0) {
- port_vlan = 0;
- }
- if (vlan != port_vlan) {
- continue;
- }
- }
- if (break_down_bonds && cfg_has_section("bonding.%s", port_name)) {
- struct svec slaves;
- svec_init(&slaves);
- cfg_get_all_keys(&slaves, "bonding.%s.slave", port_name);
- svec_append(parts, &slaves);
- svec_destroy(&slaves);
- } else {
- svec_add(parts, port_name);
- }
- }
- svec_destroy(&ports);
-}
-
-/* Add all the interfaces for 'bridge' to 'ifaces', breaking bonded interfaces
- * down into their constituent parts.
- *
- * If 'vlan' < 0, all interfaces on 'bridge' are reported. If 'vlan' == 0,
- * then only interfaces for trunk ports or ports with implicit VLAN 0 are
- * reported. If 'vlan' > 0, only interfaces with implicit VLAN 'vlan' are
- * reported. */
-static void
-get_bridge_ifaces(const char *bridge, struct svec *ifaces, int vlan)
-{
- do_get_bridge_parts(bridge, ifaces, vlan, true);
-}
-
-/* Add all the ports for 'bridge' to 'ports'. Bonded ports are reported under
- * the bond name, not broken down into their constituent interfaces.
- *
- * If 'vlan' < 0, all ports on 'bridge' are reported. If 'vlan' == 0, then
- * 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 char *bridge, struct svec *ports, int vlan)
-{
- do_get_bridge_parts(bridge, ports, vlan, false);
-}
-
-/* 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;
- int error;
- 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];
- enum netdev_flags flags;
-
- /* 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;
- }
-
- error = netdev_nodev_get_flags(iface_name, &flags);
- if (error == ENODEV) {
- VLOG_INFO_RL(&rl, "removing dead interface %s from %s",
- iface_name, br_name);
- svec_add(&delete, iface_name);
- } else if (error) {
- VLOG_INFO_RL(&rl, "unknown error %d on interface %s from %s",
- error, iface_name, br_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]);
- }
- rewrite_and_reload_config();
- cfg_unlock();
- } else {
- cfg_unlock();
- }
- svec_destroy(&delete);
-}
-
-/* Checks whether a network device named 'name' exists and returns true if so,
- * false otherwise.
- *
- * XXX it is possible that this doesn't entirely accomplish what we want in
- * context, since ovs-vswitchd.conf may cause vswitchd to create or destroy
- * network devices based on iface.*.internal settings.
- *
- * XXX may want to move this to lib/netdev.
- *
- * XXX why not just use netdev_nodev_get_flags() or similar function? */
-static bool
-netdev_exists(const char *name)
-{
- struct stat s;
- char *filename;
- int error;
-
- filename = xasprintf("/sys/class/net/%s", name);
- error = stat(filename, &s);
- free(filename);
- return !error;
-}
-
-static int
-add_bridge(const char *br_name)
-{
- if (bridge_exists(br_name)) {
- VLOG_WARN("addbr %s: bridge %s exists", br_name, br_name);
- return EEXIST;
- } else if (netdev_exists(br_name)) {
- if (cfg_get_bool(0, "iface.%s.fake-bridge", br_name)) {
- VLOG_WARN("addbr %s: %s exists as a fake bridge",
- br_name, br_name);
- return 0;
- } else {
- VLOG_WARN("addbr %s: cannot create bridge %s because a network "
- "device named %s already exists",
- br_name, br_name, br_name);
- return EEXIST;
- }
- }
-
- cfg_add_entry("bridge.%s.port=%s", br_name, br_name);
- VLOG_INFO("addbr %s: success", br_name);
-
- return 0;
-}
-
-static int
-del_bridge(const char *br_name)
-{
- if (!bridge_exists(br_name)) {
- VLOG_WARN("delbr %s: no bridge named %s", br_name, br_name);
- return ENXIO;
- }
-
- cfg_del_section("bridge.%s", br_name);
- VLOG_INFO("delbr %s: success", br_name);
-
- return 0;
-}
-