-static struct ovsrec_bridge *
-find_bridge(const struct ovsrec_open_vswitch *ovs, const char *br_name)
-{
- size_t i;
-
- for (i = 0; i < ovs->n_bridges; i++) {
- if (!strcmp(br_name, ovs->bridges[i]->name)) {
- return ovs->bridges[i];
- }
- }
-
- return NULL;
-}
-
-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 void
-do_get_bridge_parts(const struct ovsrec_bridge *br, struct svec *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) {
- continue;
- }
- }
- 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);
- }
- } 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 struct ovsrec_bridge *br, struct svec *ifaces,
- int vlan)
-{
- do_get_bridge_parts(br, 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 struct ovsrec_bridge *br, struct svec *ports,
- int vlan)
-{
- do_get_bridge_parts(br, ports, vlan, false);
-}
-
-static struct ovsdb_idl_txn *
-txn_from_openvswitch(const struct ovsrec_open_vswitch *ovs)
-{
- return ovsdb_idl_txn_get(&ovs->header_);
-}
-
-static bool
-port_is_fake_bridge(const struct ovsrec_port *port)
-{
- return (port->fake_bridge
- && port->tag
- && *port->tag >= 1 && *port->tag <= 4095);
-}
-
-static void
-ovs_insert_bridge(const struct ovsrec_open_vswitch *ovs,
- struct ovsrec_bridge *bridge)
-{
- struct ovsrec_bridge **bridges;
- size_t i;
-
- bridges = xmalloc(sizeof *ovs->bridges * (ovs->n_bridges + 1));
- for (i = 0; i < ovs->n_bridges; i++) {
- bridges[i] = ovs->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)
-{
- return
- json_array_create_1(
- json_array_create_3(
- json_string_create("_uuid"),
- json_string_create("=="),
- json_array_create_2(
- json_string_create("uuid"),
- json_string_create_nocopy(
- xasprintf(UUID_FMT, UUID_ARGS(uuid))))));
-}
-
-/* Commits 'txn'. If 'wait_for_reload' is true, also waits for Open vSwitch to
- reload the configuration before returning.
-
- Returns EAGAIN if the caller should try the operation again, 0 on success,
- otherwise a positive errno value. */
-static int
-commit_txn(struct ovsdb_idl_txn *txn, bool wait_for_reload)
-{
- struct ovsdb_idl *idl = ovsdb_idl_txn_get_idl (txn);
- enum ovsdb_idl_txn_status status;
- int64_t next_cfg = 0;
-
- if (wait_for_reload) {
- const struct ovsrec_open_vswitch *ovs = ovsrec_open_vswitch_first(idl);
- struct json *where = where_uuid_equals(&ovs->header_.uuid);
- ovsdb_idl_txn_increment(txn, "Open_vSwitch", "next_cfg", where);
- json_destroy(where);
- }
- status = ovsdb_idl_txn_commit_block(txn);
- if (wait_for_reload && status == TXN_SUCCESS) {
- next_cfg = ovsdb_idl_txn_get_increment_new_value(txn);
- }
- ovsdb_idl_txn_destroy(txn);
-
- switch (status) {
- case TXN_INCOMPLETE:
- NOT_REACHED();
-
- case TXN_ABORTED:
- VLOG_ERR_RL(&rl, "OVSDB transaction unexpectedly aborted");
- return ECONNABORTED;
-
- case TXN_UNCHANGED:
- return 0;
-
- case TXN_SUCCESS:
- if (wait_for_reload) {
- for (;;) {
- /* We can't use 'ovs' any longer because ovsdb_idl_run() can
- * destroy it. */
- const struct ovsrec_open_vswitch *ovs2;
-
- ovsdb_idl_run(idl);
- OVSREC_OPEN_VSWITCH_FOR_EACH (ovs2, idl) {
- if (ovs2->cur_cfg >= next_cfg) {
- goto done;
- }
- }
- ovsdb_idl_wait(idl);
- poll_block();
- }
- done: ;
- }
- return 0;
-
- case TXN_TRY_AGAIN:
- VLOG_ERR_RL(&rl, "OVSDB transaction needs retry");
- return EAGAIN;
-
- case TXN_ERROR:
- VLOG_ERR_RL(&rl, "OVSDB transaction failed: %s",
- ovsdb_idl_txn_get_error(txn));
- return EBUSY;
-
- default:
- NOT_REACHED();
- }
-}
-
-static int
-add_bridge(struct ovsdb_idl *idl, const struct ovsrec_open_vswitch *ovs,
- const char *br_name)
-{
- struct ovsrec_bridge *br;
- struct ovsrec_port *port;
- struct ovsrec_interface *iface;
- struct ovsdb_idl_txn *txn;
-
- if (find_bridge(ovs, br_name)) {
- VLOG_WARN("addbr %s: bridge %s exists", br_name, br_name);
- return EEXIST;
- } else if (netdev_exists(br_name)) {
- size_t i;
-
- for (i = 0; i < ovs->n_bridges; i++) {
- size_t j;
- struct ovsrec_bridge *br_cfg = ovs->bridges[i];
-
- for (j = 0; j < br_cfg->n_ports; j++) {
- if (port_is_fake_bridge(br_cfg->ports[j])) {
- VLOG_WARN("addbr %s: %s exists as a fake bridge",
- br_name, br_name);
- return 0;
- }
- }
- }
-
- VLOG_WARN("addbr %s: cannot create bridge %s because a network "
- "device named %s already exists",
- br_name, br_name, br_name);
- return EEXIST;
- }
-
- txn = ovsdb_idl_txn_create(idl);
-
- ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: addbr %s", br_name);
-
- iface = ovsrec_interface_insert(txn_from_openvswitch(ovs));
- ovsrec_interface_set_name(iface, br_name);
-
- 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,
- const struct ovsrec_bridge *br, const char *port_name)
-{
- struct ovsrec_interface *iface;
- struct ovsrec_port *port;
- struct ovsrec_port **ports;
- size_t i;
-
- /* xxx Check conflicts? */
- iface = ovsrec_interface_insert(txn_from_openvswitch(ovs));
- ovsrec_interface_set_name(iface, port_name);
-
- port = ovsrec_port_insert(txn_from_openvswitch(ovs));
- ovsrec_port_set_name(port, port_name);
- ovsrec_port_set_interfaces(port, &iface, 1);
-
- ports = xmalloc(sizeof *br->ports * (br->n_ports + 1));
- for (i = 0; i < br->n_ports; i++) {
- ports[i] = br->ports[i];
- }
- ports[br->n_ports] = port;
- ovsrec_bridge_set_ports(br, ports, br->n_ports + 1);
- free(ports);
-}
-
-/* Deletes 'port' from 'br'.
- *
- * After calling this function, 'port' must not be referenced again. */
-static void
-del_port(const struct ovsrec_bridge *br, const struct ovsrec_port *port)
-{
- struct ovsrec_port **ports;
- size_t i, n;
-
- /* Remove 'port' from the bridge's list of ports. */
- ports = xmalloc(sizeof *br->ports * br->n_ports);
- for (i = n = 0; i < br->n_ports; i++) {
- if (br->ports[i] != port) {
- ports[n++] = br->ports[i];
- }
- }
- ovsrec_bridge_set_ports(br, ports, n);
- free(ports);
-}
-
-/* Delete 'iface' from 'port' (which must be within 'br'). If 'iface' was
- * 'port''s only interface, delete 'port' from 'br' also.
- *
- * After calling this function, 'iface' must not be referenced again. */
-static void
-del_interface(const struct ovsrec_bridge *br,
- const struct ovsrec_port *port,
- const struct ovsrec_interface *iface)
-{
- if (port->n_interfaces == 1) {
- del_port(br, port);
- } else {
- struct ovsrec_interface **ifaces;
- size_t i, n;
-
- ifaces = xmalloc(sizeof *port->interfaces * port->n_interfaces);
- for (i = n = 0; i < port->n_interfaces; i++) {
- if (port->interfaces[i] != iface) {
- ifaces[n++] = port->interfaces[i];
- }
- }
- ovsrec_port_set_interfaces(port, ifaces, n);
- free(ifaces);
- }
-}
-
-/* Find and return a port within 'br' named 'port_name'. */
-static const struct ovsrec_port *
-find_port(const struct ovsrec_bridge *br, const char *port_name)
-{
- size_t i;
-
- for (i = 0; i < br->n_ports; i++) {
- struct ovsrec_port *port = br->ports[i];
- if (!strcmp(port_name, port->name)) {
- return port;
- }
- }
- return NULL;
-}
-
-/* Find and return an interface within 'br' named 'iface_name'. */
-static const struct ovsrec_interface *
-find_interface(const struct ovsrec_bridge *br, const char *iface_name,
- struct ovsrec_port **portp)
-{
- size_t i;
-
- for (i = 0; i < br->n_ports; i++) {
- struct ovsrec_port *port = br->ports[i];
- size_t j;
-
- for (j = 0; j < port->n_interfaces; j++) {
- struct ovsrec_interface *iface = port->interfaces[j];
- if (!strcmp(iface->name, iface_name)) {
- *portp = port;
- return iface;
- }
- }
- }
-
- *portp = NULL;
- return NULL;
-}
-
-static int
-del_bridge(struct ovsdb_idl *idl,
- const struct ovsrec_open_vswitch *ovs, const char *br_name)
-{
- struct ovsrec_bridge *br = find_bridge(ovs, br_name);
- struct ovsrec_bridge **bridges;
- struct ovsdb_idl_txn *txn;
- size_t i, n;
-
- if (!br) {
- VLOG_WARN("delbr %s: no bridge named %s", br_name, br_name);
- return ENXIO;
- }
-
- txn = ovsdb_idl_txn_create(idl);
-
- ovsdb_idl_txn_add_comment(txn, "ovs-brcompatd: delbr %s", br_name);
-
- /* 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++) {
- if (ovs->bridges[i] != br) {
- bridges[n++] = ovs->bridges[i];
- }
- }
- ovsrec_open_vswitch_set_bridges(ovs, bridges, n);
- free(bridges);
-
- return commit_txn(txn, true);
-}
-