aboutsummaryrefslogtreecommitdiff
path: root/vswitchd/ovs-brcompatd.c
diff options
context:
space:
mode:
authorBen Pfaff <blp@nicira.com>2009-08-07 15:11:40 -0700
committerBen Pfaff <blp@nicira.com>2009-08-07 15:11:40 -0700
commitdb322751d8bba32152e89eea476cb47a010616b1 (patch)
tree0813665b87e910e7dfdb9d0fe96cf6836b30c062 /vswitchd/ovs-brcompatd.c
parentae1281cfa015b710817822002f21a4f6195cb740 (diff)
brcompat: Move BRCTL_GET_BRIDGES, BRCTL_GET_PORT_LIST into userspace.
The Citrix QA scripts assume that "brctl show" will show a topology as if the Linux bridge were still in use; that is, as if there were one bridge per VLAN and as if bonds were network devices of their own instead of separate devices. However, we were showing the datapath topology, i.e. all VLANs and bond devices lumped together into a single datapath. This commit fixes the VLAN end of the problem, by moving the implementation of the ioctls that brctl uses into userspace in ovs-brcompatd and putting the necessary translation logic into ovs-brcompatd. By itself, this commit does not fix the problem for bonds: the port name for a bond does not (normally) under Open vSwitch exist as an actual Linux network device, and thus it has no ifindex, and so ovs-brcompatd can't pass it back to the kernel to report to brctl. This fix will have to wait for another commit. Bug NIC-19.
Diffstat (limited to 'vswitchd/ovs-brcompatd.c')
-rw-r--r--vswitchd/ovs-brcompatd.c166
1 files changed, 153 insertions, 13 deletions
diff --git a/vswitchd/ovs-brcompatd.c b/vswitchd/ovs-brcompatd.c
index 3b24bc9f..a510f166 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.
*
@@ -660,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;
@@ -740,6 +759,119 @@ 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();
+ 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);
+ 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 +934,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;
}