-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;
-}
-
-/* Get all the interfaces for 'bridge' as '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 implict VLAN 'vlan' are
- * reported. */
-static void
-get_bridge_ifaces(const char *bridge, struct svec *ifaces, int vlan)
-{
- struct svec ports;
- int i;
-
- svec_init(&ports);
- svec_init(ifaces);
- 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 (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(ifaces, &slaves);
- svec_destroy(&slaves);
- } else {
- svec_add(ifaces, port_name);
- }
- }
- svec_destroy(&ports);
-}
-
-/* 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. */
- 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]);
- }
- rewrite_and_reload_config();
- cfg_unlock();
- } else {
- cfg_unlock();
- }
- svec_destroy(&delete);
-}
-
-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;
-}
-