X-Git-Url: https://pintos-os.org/cgi-bin/gitweb.cgi?a=blobdiff_plain;f=vswitchd%2Fovs-brcompatd.c;h=13bb843dd624e5834fae8648414ab7a135f5520a;hb=42061b2a5b79d44c0ff9442a8203f0c7672ee9cf;hp=e569c74d7575135f155fa952a3173858a85f8c1f;hpb=41e754bcb40f78f5a2a790a4b196433cd1afa304;p=openvswitch diff --git a/vswitchd/ovs-brcompatd.c b/vswitchd/ovs-brcompatd.c index e569c74d..13bb843d 100644 --- a/vswitchd/ovs-brcompatd.c +++ b/vswitchd/ovs-brcompatd.c @@ -240,21 +240,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,19 +260,44 @@ 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 @@ -302,6 +320,7 @@ 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]; @@ -345,7 +364,6 @@ prune_ports(void) svec_destroy(&delete); } - /* Checks whether a network device named 'name' exists and returns true if so, * false otherwise. * @@ -507,7 +525,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 @@ -564,6 +582,33 @@ get_bridge_containing_port(const char *port_name) return xmemdup0(start, end - start); } +static int +linux_bridge_to_ovs_bridge(const char *linux_bridge, + char **ovs_bridge, int *br_vlan) +{ + if (bridge_exists(linux_bridge)) { + /* Bridge name is the same. We are interested in VLAN 0. */ + *ovs_bridge = xstrdup(linux_bridge); + *br_vlan = 0; + return 0; + } else { + /* No such Open vSwitch bridge 'linux_bridge', but there might be an + * internal port named 'linux_bridge' on some other bridge + * 'ovs_bridge'. If so then we are interested in the VLAN assigned to + * port 'linux_bridge' on the bridge named 'ovs_bridge'. */ + const char *port_name = linux_bridge; + + *ovs_bridge = get_bridge_containing_port(port_name); + *br_vlan = cfg_get_vlan(0, "vlan.%s.tag", port_name); + if (*ovs_bridge && *br_vlan >= 0) { + return 0; + } else { + free(*ovs_bridge); + return ENODEV; + } + } +} + static int handle_fdb_query_cmd(struct ofpbuf *buffer) { @@ -615,24 +660,10 @@ handle_fdb_query_cmd(struct ofpbuf *buffer) /* Figure out vswitchd bridge and VLAN. */ cfg_read(); - if (bridge_exists(linux_bridge)) { - /* Bridge name is the same. We are interested in VLAN 0. */ - ovs_bridge = xstrdup(linux_bridge); - br_vlan = 0; - } else { - /* No such Open vSwitch bridge 'linux_bridge', but there might be an - * internal port named 'linux_bridge' on some other bridge - * 'ovs_bridge'. If so then we are interested in the VLAN assigned to - * port 'linux_bridge' on the bridge named 'ovs_bridge'. */ - const char *port_name = linux_bridge; - - ovs_bridge = get_bridge_containing_port(port_name); - br_vlan = cfg_get_vlan(0, "vlan.%s.tag", port_name); - if (!ovs_bridge || br_vlan < 0) { - free(ovs_bridge); - send_simple_reply(seq, ENODEV); - return error; - } + error = linux_bridge_to_ovs_bridge(linux_bridge, &ovs_bridge, &br_vlan); + if (error) { + send_simple_reply(seq, error); + return error; } /* Fetch the forwarding database using ovs-appctl. */ @@ -647,6 +678,7 @@ 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; @@ -727,6 +759,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) { @@ -789,6 +937,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; } @@ -838,7 +994,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)) { @@ -855,8 +1010,11 @@ rtnl_recv_update(void) if (netdev_nodev_get_flags(port_name, &flags) == ENODEV) { /* 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); @@ -864,6 +1022,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