summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Graf <tgraf@redhat.com>2011-09-16 12:57:52 +0200
committerThomas Graf <tgraf@redhat.com>2011-09-16 12:57:52 +0200
commit96f17ce146b35fda3f745a418352d731c522265e (patch)
treeebe42825cd376471ec8c0dc3326a29ff0a85cdb0
parent5151cbc2f6e5ca81cfc66eeb1d4a5c6c4e886108 (diff)
downloadlibnl-96f17ce146b35fda3f745a418352d731c522265e.tar.gz
bonding: API to create/enslave/release
Although it has been possible to create bonding devices, enslave and release using the regular link API. The added API simplifies usage and hides some of the compatibility logic. F.e. enslave() and release() will both verify that the master assignment has in fact been changed and return -NLE_OPNOTSUPP if it did not. Also the API will make sure to use RTM_NEWLINK or RTM_SETLINK depending on what is availble. Examples are provided in src/ as nl-link-enslave.c and nl-link-release.c
-rw-r--r--include/netlink/route/link/bonding.h37
-rw-r--r--lib/route/link/bonding.c176
-rw-r--r--src/Makefile.am4
-rw-r--r--src/nl-link-enslave.c50
-rw-r--r--src/nl-link-release.c45
5 files changed, 311 insertions, 1 deletions
diff --git a/include/netlink/route/link/bonding.h b/include/netlink/route/link/bonding.h
new file mode 100644
index 0000000..cca777a
--- /dev/null
+++ b/include/netlink/route/link/bonding.h
@@ -0,0 +1,37 @@
+/*
+ * netlink/route/link/bonding.h Bonding Interface
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#ifndef NETLINK_LINK_VLAN_H_
+#define NETLINK_LINK_VLAN_H_
+
+#include <netlink/netlink.h>
+#include <netlink/route/link.h>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+extern int rtnl_link_bond_add(struct nl_sock *, const char *,
+ struct rtnl_link *);
+
+extern int rtnl_link_bond_enslave_ifindex(struct nl_sock *, int, int);
+extern int rtnl_link_bond_enslave(struct nl_sock *, struct rtnl_link *,
+ struct rtnl_link *);
+
+extern int rtnl_link_bond_release_ifindex(struct nl_sock *, int);
+extern int rtnl_link_bond_release(struct nl_sock *, struct rtnl_link *);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
+
diff --git a/lib/route/link/bonding.c b/lib/route/link/bonding.c
index 176be27..5788f69 100644
--- a/lib/route/link/bonding.c
+++ b/lib/route/link/bonding.c
@@ -24,6 +24,182 @@
#include <netlink/netlink.h>
#include <netlink/route/link/api.h>
+/**
+ * Create a new kernel bonding device
+ * @arg sock netlink socket
+ * @arg name name of bonding device or NULL
+ * @arg opts bonding options (currently unused)
+ *
+ * Creates a new bonding device in the kernel. If no name is
+ * provided, the kernel will automatically pick a name of the
+ * form "type%d" (e.g. bond0, vlan1, etc.)
+ *
+ * The \a opts argument is currently unused. In the future, it
+ * may be used to carry additional bonding options to be set
+ * when creating the bonding device.
+ *
+ * @note When letting the kernel assign a name, it will become
+ * difficult to retrieve the interface afterwards because
+ * you have to guess the name the kernel has chosen. It is
+ * therefore not recommended to not provide a device name.
+ *
+ * @see rtnl_link_bond_enslave()
+ * @see rtnl_link_bond_release()
+ *
+ * @return 0 on success or a negative error code
+ */
+int rtnl_link_bond_add(struct nl_sock *sock, const char *name,
+ struct rtnl_link *opts)
+{
+ struct rtnl_link *link;
+ int err;
+
+ if (!(link = rtnl_link_alloc()))
+ return -NLE_NOMEM;
+
+ if (!name) {
+ if (opts)
+ name = rtnl_link_get_name(opts);
+
+ if (!name)
+ return -NLE_MISSING_ATTR;
+ }
+
+ if ((err = rtnl_link_set_type(link, "bond")) < 0)
+ goto errout;
+
+
+ rtnl_link_set_name(link, name);
+
+ err = rtnl_link_add(sock, link, NLM_F_CREATE);
+errout:
+ rtnl_link_put(link);
+
+ return err;
+}
+
+/**
+ * Add a link to a bond (enslave)
+ * @arg sock netlink socket
+ * @arg master ifindex of bonding master
+ * @arg slave ifindex of slave link to add to bond
+ *
+ * This function is identical to rtnl_link_bond_enslave() except that
+ * it takes interface indices instead of rtnl_link objcets.
+ *
+ * @see rtnl_link_bond_enslave()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_enslave_ifindex(struct nl_sock *sock, int master,
+ int slave)
+{
+ struct rtnl_link *link;
+ int err;
+
+ if (!(link = rtnl_link_alloc()))
+ return -NLE_NOMEM;
+
+ if ((err = rtnl_link_set_type(link, "bond")) < 0)
+ goto errout;
+
+ rtnl_link_set_ifindex(link, slave);
+ rtnl_link_set_master(link, master);
+
+ if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
+ goto errout;
+
+ rtnl_link_put(link);
+
+ /*
+ * Due to the kernel not signaling whether this opertion is
+ * supported or not, we will retrieve the attribute to see if the
+ * request was successful. If the master assigned remains unchanged
+ * we will return NLE_OPNOTSUPP to allow performing backwards
+ * compatibility of some sort.
+ */
+ if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
+ return err;
+
+ if (rtnl_link_get_master(link) != master)
+ err = -NLE_OPNOTSUPP;
+
+errout:
+ rtnl_link_put(link);
+
+ return err;
+}
+
+/**
+ * Add a link to a bond (enslave)
+ * @arg sock netlink socket
+ * @arg master bonding master
+ * @arg slave slave link to add to bond
+ *
+ * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to
+ * the master and sends the request via the specified netlink socket.
+ *
+ * @note The feature of enslaving/releasing via netlink has only been added
+ * recently to the kernel (Feb 2011). Also, the kernel does not signal
+ * if the operation is not supported. Therefore this function will
+ * verify if the master assignment has changed and will return
+ * -NLE_OPNOTSUPP if it did not.
+ *
+ * @see rtnl_link_bond_enslave_ifindex()
+ * @see rtnl_link_bond_release()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_enslave(struct nl_sock *sock, struct rtnl_link *master,
+ struct rtnl_link *slave)
+{
+ return rtnl_link_bond_enslave_ifindex(sock,
+ rtnl_link_get_ifindex(master),
+ rtnl_link_get_ifindex(slave));
+}
+
+/**
+ * Release a link from a bond
+ * @arg sock netlink socket
+ * @arg slave slave link to be released
+ *
+ * This function is identical to rtnl_link_bond_release() except that
+ * it takes an interface index instead of a rtnl_link object.
+ *
+ * @see rtnl_link_bond_release()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_release_ifindex(struct nl_sock *sock, int slave)
+{
+ return rtnl_link_bond_enslave_ifindex(sock, 0, slave);
+}
+
+/**
+ * Release a link from a bond
+ * @arg sock netlink socket
+ * @arg slave slave link to be released
+ *
+ * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from
+ * its master and sends the request via the specified netlink socket.
+ *
+ * @note The feature of enslaving/releasing via netlink has only been added
+ * recently to the kernel (Feb 2011). Also, the kernel does not signal
+ * if the operation is not supported. Therefore this function will
+ * verify if the master assignment has changed and will return
+ * -NLE_OPNOTSUPP if it did not.
+ *
+ * @see rtnl_link_bond_release_ifindex()
+ * @see rtnl_link_bond_enslave()
+ *
+ * @return 0 on success or a negative error code.
+ */
+int rtnl_link_bond_release(struct nl_sock *sock, struct rtnl_link *slave)
+{
+ return rtnl_link_bond_release_ifindex(sock,
+ rtnl_link_get_ifindex(slave));
+}
+
static struct rtnl_link_info_ops bonding_info_ops = {
.io_name = "bond",
};
diff --git a/src/Makefile.am b/src/Makefile.am
index 3b5c140..b59f96a 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -33,7 +33,9 @@ noinst_PROGRAMS = \
nl-route-add nl-route-delete nl-route-get nl-route-list \
nl-fib-lookup \
nl-list-caches nl-list-sockets \
- nl-util-addr
+ nl-util-addr \
+ nl-link-enslave \
+ nl-link-release
genl_ctrl_list_SOURCES = genl-ctrl-list.c
diff --git a/src/nl-link-enslave.c b/src/nl-link-enslave.c
new file mode 100644
index 0000000..2b5d47d
--- /dev/null
+++ b/src/nl-link-enslave.c
@@ -0,0 +1,50 @@
+/*
+ * src/nl-link-enslave.c Enslave a link
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+#include <netlink/route/link/bonding.h>
+
+int main(int argc, char *argv[])
+{
+ struct nl_sock *sock;
+ struct nl_cache *link_cache;
+ struct rtnl_link *master, *slave;
+ int err;
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: nl-link-enslave master slave\n");
+ return 1;
+ }
+
+ sock = nl_cli_alloc_socket();
+ nl_cli_connect(sock, NETLINK_ROUTE);
+ link_cache = nl_cli_link_alloc_cache(sock);
+
+ if (!(master = rtnl_link_get_by_name(link_cache, argv[1]))) {
+ fprintf(stderr, "Unknown link: %s\n", argv[1]);
+ return 1;
+ }
+
+ if (!(slave = rtnl_link_get_by_name(link_cache, argv[2]))) {
+ fprintf(stderr, "Unknown link: %s\n", argv[2]);
+ return 1;
+ }
+
+ if ((err = rtnl_link_bond_enslave(sock, master, slave)) < 0) {
+ fprintf(stderr, "Unable to enslave %s to %s: %s\n",
+ argv[2], argv[1], nl_geterror(err));
+ return 1;
+ }
+
+ return 0;
+}
+
diff --git a/src/nl-link-release.c b/src/nl-link-release.c
new file mode 100644
index 0000000..4c9f15a
--- /dev/null
+++ b/src/nl-link-release.c
@@ -0,0 +1,45 @@
+/*
+ * src/nl-link-release.c release a link
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation version 2.1
+ * of the License.
+ *
+ * Copyright (c) 2011 Thomas Graf <tgraf@suug.ch>
+ */
+
+#include <netlink/cli/utils.h>
+#include <netlink/cli/link.h>
+#include <netlink/route/link/bonding.h>
+
+int main(int argc, char *argv[])
+{
+ struct nl_sock *sock;
+ struct nl_cache *link_cache;
+ struct rtnl_link *slave;
+ int err;
+
+ if (argc < 2) {
+ fprintf(stderr, "Usage: nl-link-release slave\n");
+ return 1;
+ }
+
+ sock = nl_cli_alloc_socket();
+ nl_cli_connect(sock, NETLINK_ROUTE);
+ link_cache = nl_cli_link_alloc_cache(sock);
+
+ if (!(slave = rtnl_link_get_by_name(link_cache, argv[1]))) {
+ fprintf(stderr, "Unknown link: %s\n", argv[1]);
+ return 1;
+ }
+
+ if ((err = rtnl_link_bond_release(sock, slave)) < 0) {
+ fprintf(stderr, "Unable to release slave %s: %s\n",
+ argv[1], nl_geterror(err));
+ return 1;
+ }
+
+ return 0;
+}
+