dect
/
libnl
Archived
13
0
Fork 0

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
This commit is contained in:
Thomas Graf 2011-09-16 12:57:52 +02:00
parent 5151cbc2f6
commit 96f17ce146
5 changed files with 311 additions and 1 deletions

View File

@ -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

View File

@ -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",
};

View File

@ -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

50
src/nl-link-enslave.c Normal file
View File

@ -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;
}

45
src/nl-link-release.c Normal file
View File

@ -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;
}