X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fovs-brcompatd.c;h=d4a59c342419eabb466991b0301d7e1271f2e2e4;hb=9678a9b66c5a57fb1dd88b8f9f1e8111e91950dc;hp=3b24bc9fd87f5318015467513fbb8928ad3190c3;hpb=ae1281cfa015b710817822002f21a4f6195cb740;p=openvswitch diff --git a/vswitchd/ovs-brcompatd.c b/vswitchd/ovs-brcompatd.c index 3b24bc9f..d4a59c34 100644 --- a/vswitchd/ovs-brcompatd.c +++ b/vswitchd/ovs-brcompatd.c @@ -38,7 +38,6 @@ #include "coverage.h" #include "daemon.h" #include "dirs.h" -#include "dpif.h" #include "dynamic-string.h" #include "fatal-signal.h" #include "fault.h" @@ -240,21 +239,14 @@ rewrite_and_reload_config(void) 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) +do_get_bridge_parts(const char *bridge, struct svec *parts, int vlan, + bool break_down_bonds) { 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]; @@ -267,26 +259,50 @@ get_bridge_ifaces(const char *bridge, struct svec *ifaces, int vlan) continue; } } - if (cfg_has_section("bonding.%s", port_name)) { + 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(ifaces, &slaves); + svec_append(parts, &slaves); svec_destroy(&slaves); } else { - svec_add(ifaces, port_name); + 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)) { @@ -302,10 +318,10 @@ prune_ports(void) 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. @@ -316,14 +332,10 @@ prune_ports(void) continue; } - error = netdev_nodev_get_flags(iface_name, &flags); - if (error == ENODEV) { + if (!netdev_exists(iface_name)) { 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); @@ -345,30 +357,6 @@ prune_ports(void) 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) { @@ -507,7 +495,7 @@ del_port(const char *br_name, const char *port_name) { cfg_del_entry("bridge.%s.port=%s", br_name, port_name); cfg_del_match("bonding.*.slave=%s", port_name); - cfg_del_match("vlan.%s.*", port_name); + cfg_del_match("vlan.%s.[!0-9]*", port_name); } static int @@ -660,14 +648,21 @@ handle_fdb_query_cmd(struct ofpbuf *buffer) /* 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); get_bridge_ifaces(ovs_bridge, &ifaces, br_vlan); local_macs = xmalloc(ifaces.n * sizeof *local_macs); n_local_macs = 0; for (i = 0; i < ifaces.n; i++) { const char *iface_name = ifaces.names[i]; struct mac *mac = &local_macs[n_local_macs]; - if (!netdev_nodev_get_etheraddr(iface_name, mac->addr)) { - n_local_macs++; + struct netdev *netdev; + + error = netdev_open(iface_name, NETDEV_ETH_TYPE_NONE, &netdev); + if (netdev) { + if (!netdev_get_etheraddr(netdev, mac->addr)) { + n_local_macs++; + } + netdev_close(netdev); } } svec_destroy(&ifaces); @@ -740,6 +735,122 @@ handle_fdb_query_cmd(struct ofpbuf *buffer) return 0; } +static void +send_ifindex_reply(uint32_t seq, struct svec *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) { + int ifindex = if_nametoindex(iface); + if (ifindex) { + indices[n_indices++] = ifindex; + } + } + + /* Compose and send reply. */ + reply = compose_reply(seq, 0); + nl_msg_put_unspec(reply, BRC_GENL_A_IFINDEXES, + indices, n_indices * sizeof *indices); + send_reply(reply); + + /* Free memory. */ + free(indices); +} + +static int +handle_get_bridges_cmd(struct ofpbuf *buffer) +{ + struct svec bridges; + const char *br_name; + size_t i; + + uint32_t seq; + + int error; + + /* Parse Netlink command. + * + * The command doesn't actually have any arguments, but we need the + * sequence number to send the reply. */ + error = parse_command(buffer, &seq, NULL, NULL, NULL, NULL); + if (error) { + return error; + } + + /* Get all the real bridges and all the fake ones. */ + cfg_read(); + svec_init(&bridges); + cfg_get_subsections(&bridges, "bridge"); + SVEC_FOR_EACH (i, br_name, &bridges) { + const char *iface_name; + struct svec ifaces; + size_t j; + + svec_init(&ifaces); + get_bridge_ifaces(br_name, &ifaces, -1); + SVEC_FOR_EACH (j, iface_name, &ifaces) { + if (cfg_get_bool(0, "iface.%s.fake-bridge", iface_name)) { + svec_add(&bridges, iface_name); + } + } + svec_destroy(&ifaces); + } + + send_ifindex_reply(seq, &bridges); + svec_destroy(&bridges); + + return 0; +} + +static int +handle_get_ports_cmd(struct ofpbuf *buffer) +{ + uint32_t seq; + + const char *linux_bridge; + char *ovs_bridge; + int br_vlan; + + struct svec ports; + + int error; + + /* Parse Netlink command. */ + error = parse_command(buffer, &seq, &linux_bridge, NULL, NULL, NULL); + if (error) { + return error; + } + + cfg_read(); + error = linux_bridge_to_ovs_bridge(linux_bridge, &ovs_bridge, &br_vlan); + if (error) { + send_simple_reply(seq, error); + return error; + } + + svec_init(&ports); + get_bridge_ports(ovs_bridge, &ports, br_vlan); + svec_sort(&ports); + svec_del(&ports, linux_bridge); + send_ifindex_reply(seq, &ports); /* XXX bonds won't show up */ + svec_destroy(&ports); + + free(ovs_bridge); + + return 0; +} + static int brc_recv_update(void) { @@ -802,6 +913,14 @@ brc_recv_update(void) retval = handle_fdb_query_cmd(buffer); break; + case BRC_GENL_C_GET_BRIDGES: + retval = handle_get_bridges_cmd(buffer); + break; + + case BRC_GENL_C_GET_PORTS: + retval = handle_get_ports_cmd(buffer); + break; + default: retval = EPROTO; } @@ -851,8 +970,6 @@ rtnl_recv_update(void) const char *port_name = nl_attr_get_string(attrs[IFLA_IFNAME]); char br_name[IFNAMSIZ]; uint32_t br_idx = nl_attr_get_u32(attrs[IFLA_MASTER]); - struct svec ports; - enum netdev_flags flags; if (!if_indextoname(br_idx, br_name)) { ofpbuf_delete(buf); @@ -866,10 +983,13 @@ rtnl_recv_update(void) return; } - if (netdev_nodev_get_flags(port_name, &flags) == ENODEV) { + if (!netdev_exists(port_name)) { /* Network device is really gone. */ + struct svec ports; + VLOG_INFO("network device %s destroyed, " "removing from bridge %s", port_name, br_name); + svec_init(&ports); cfg_get_all_keys(&ports, "bridge.%s.port", br_name); svec_sort(&ports); @@ -877,6 +997,7 @@ rtnl_recv_update(void) del_port(br_name, port_name); rewrite_and_reload_config(); } + svec_destroy(&ports); } else { /* A network device by that name exists even though the kernel * told us it had disappeared. Probably, what happened was @@ -970,6 +1091,7 @@ main(int argc, char *argv[]) for (;;) { unixctl_server_run(unixctl); brc_recv_update(); + netdev_run(); /* If 'prune_timeout' is non-zero, we actively prune from the * config file any 'bridge..port' entries that are no @@ -991,6 +1113,7 @@ main(int argc, char *argv[]) nl_sock_wait(brc_sock, POLLIN); unixctl_server_wait(unixctl); + netdev_wait(); poll_block(); }