Home | History | Annotate | Download | only in link
      1 /*
      2  * lib/route/link/bonding.c	Bonding Link Module
      3  *
      4  *	This library is free software; you can redistribute it and/or
      5  *	modify it under the terms of the GNU Lesser General Public
      6  *	License as published by the Free Software Foundation version 2.1
      7  *	of the License.
      8  *
      9  * Copyright (c) 2011-2013 Thomas Graf <tgraf (at) suug.ch>
     10  */
     11 
     12 /**
     13  * @ingroup link
     14  * @defgroup bonding Bonding
     15  *
     16  * @details
     17  * \b Link Type Name: "bond"
     18  *
     19  * @route_doc{link_bonding, Bonding Documentation}
     20  * @{
     21  */
     22 
     23 #include <netlink-private/netlink.h>
     24 #include <netlink/netlink.h>
     25 #include <netlink-private/route/link/api.h>
     26 
     27 /**
     28  * Allocate link object of type bond
     29  *
     30  * @return Allocated link object or NULL.
     31  */
     32 struct rtnl_link *rtnl_link_bond_alloc(void)
     33 {
     34 	struct rtnl_link *link;
     35 	int err;
     36 
     37 	if (!(link = rtnl_link_alloc()))
     38 		return NULL;
     39 
     40 	if ((err = rtnl_link_set_type(link, "bond")) < 0) {
     41 		rtnl_link_put(link);
     42 		return NULL;
     43 	}
     44 
     45 	return link;
     46 }
     47 
     48 /**
     49  * Create a new kernel bonding device
     50  * @arg sock		netlink socket
     51  * @arg name		name of bonding device or NULL
     52  * @arg opts		bonding options (currently unused)
     53  *
     54  * Creates a new bonding device in the kernel. If no name is
     55  * provided, the kernel will automatically pick a name of the
     56  * form "type%d" (e.g. bond0, vlan1, etc.)
     57  *
     58  * The \a opts argument is currently unused. In the future, it
     59  * may be used to carry additional bonding options to be set
     60  * when creating the bonding device.
     61  *
     62  * @note When letting the kernel assign a name, it will become
     63  *       difficult to retrieve the interface afterwards because
     64  *       you have to guess the name the kernel has chosen. It is
     65  *       therefore not recommended to not provide a device name.
     66  *
     67  * @see rtnl_link_bond_enslave()
     68  * @see rtnl_link_bond_release()
     69  *
     70  * @return 0 on success or a negative error code
     71  */
     72 int rtnl_link_bond_add(struct nl_sock *sock, const char *name,
     73 		       struct rtnl_link *opts)
     74 {
     75 	struct rtnl_link *link;
     76 	int err;
     77 
     78 	if (!(link = rtnl_link_bond_alloc()))
     79 		return -NLE_NOMEM;
     80 
     81 	if (!name && opts)
     82 		name = rtnl_link_get_name(opts);
     83 
     84 	if (name)
     85 		rtnl_link_set_name(link, name);
     86 
     87 	err = rtnl_link_add(sock, link, NLM_F_CREATE);
     88 
     89 	rtnl_link_put(link);
     90 
     91 	return err;
     92 }
     93 
     94 /**
     95  * Add a link to a bond (enslave)
     96  * @arg sock		netlink socket
     97  * @arg master		ifindex of bonding master
     98  * @arg slave		ifindex of slave link to add to bond
     99  *
    100  * This function is identical to rtnl_link_bond_enslave() except that
    101  * it takes interface indices instead of rtnl_link objcets.
    102  *
    103  * @see rtnl_link_bond_enslave()
    104  *
    105  * @return 0 on success or a negative error code.
    106  */
    107 int rtnl_link_bond_enslave_ifindex(struct nl_sock *sock, int master,
    108 				   int slave)
    109 {
    110 	struct rtnl_link *link;
    111 	int err;
    112 
    113 	if (!(link = rtnl_link_bond_alloc()))
    114 		return -NLE_NOMEM;
    115 
    116 	rtnl_link_set_ifindex(link, slave);
    117 	rtnl_link_set_master(link, master);
    118 
    119 	if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
    120 		goto errout;
    121 
    122 	rtnl_link_put(link);
    123 
    124 	/*
    125 	 * Due to the kernel not signaling whether this opertion is
    126 	 * supported or not, we will retrieve the attribute to see  if the
    127 	 * request was successful. If the master assigned remains unchanged
    128 	 * we will return NLE_OPNOTSUPP to allow performing backwards
    129 	 * compatibility of some sort.
    130 	 */
    131 	if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
    132 		return err;
    133 
    134 	if (rtnl_link_get_master(link) != master)
    135 		err = -NLE_OPNOTSUPP;
    136 
    137 errout:
    138 	rtnl_link_put(link);
    139 
    140 	return err;
    141 }
    142 
    143 /**
    144  * Add a link to a bond (enslave)
    145  * @arg sock		netlink socket
    146  * @arg master		bonding master
    147  * @arg slave		slave link to add to bond
    148  *
    149  * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to
    150  * the master and sends the request via the specified netlink socket.
    151  *
    152  * @note The feature of enslaving/releasing via netlink has only been added
    153  *       recently to the kernel (Feb 2011). Also, the kernel does not signal
    154  *       if the operation is not supported. Therefore this function will
    155  *       verify if the master assignment has changed and will return
    156  *       -NLE_OPNOTSUPP if it did not.
    157  *
    158  * @see rtnl_link_bond_enslave_ifindex()
    159  * @see rtnl_link_bond_release()
    160  *
    161  * @return 0 on success or a negative error code.
    162  */
    163 int rtnl_link_bond_enslave(struct nl_sock *sock, struct rtnl_link *master,
    164 			   struct rtnl_link *slave)
    165 {
    166 	return rtnl_link_bond_enslave_ifindex(sock,
    167 				rtnl_link_get_ifindex(master),
    168 				rtnl_link_get_ifindex(slave));
    169 }
    170 
    171 /**
    172  * Release a link from a bond
    173  * @arg sock		netlink socket
    174  * @arg slave		slave link to be released
    175  *
    176  * This function is identical to rtnl_link_bond_release() except that
    177  * it takes an interface index instead of a rtnl_link object.
    178  *
    179  * @see rtnl_link_bond_release()
    180  *
    181  * @return 0 on success or a negative error code.
    182  */
    183 int rtnl_link_bond_release_ifindex(struct nl_sock *sock, int slave)
    184 {
    185 	return rtnl_link_bond_enslave_ifindex(sock, 0, slave);
    186 }
    187 
    188 /**
    189  * Release a link from a bond
    190  * @arg sock		netlink socket
    191  * @arg slave		slave link to be released
    192  *
    193  * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from
    194  * its master and sends the request via the specified netlink socket.
    195  *
    196  * @note The feature of enslaving/releasing via netlink has only been added
    197  *       recently to the kernel (Feb 2011). Also, the kernel does not signal
    198  *       if the operation is not supported. Therefore this function will
    199  *       verify if the master assignment has changed and will return
    200  *       -NLE_OPNOTSUPP if it did not.
    201  *
    202  * @see rtnl_link_bond_release_ifindex()
    203  * @see rtnl_link_bond_enslave()
    204  *
    205  * @return 0 on success or a negative error code.
    206  */
    207 int rtnl_link_bond_release(struct nl_sock *sock, struct rtnl_link *slave)
    208 {
    209 	return rtnl_link_bond_release_ifindex(sock,
    210 				rtnl_link_get_ifindex(slave));
    211 }
    212 
    213 static struct rtnl_link_info_ops bonding_info_ops = {
    214 	.io_name		= "bond",
    215 };
    216 
    217 static void __init bonding_init(void)
    218 {
    219 	rtnl_link_register_info(&bonding_info_ops);
    220 }
    221 
    222 static void __exit bonding_exit(void)
    223 {
    224 	rtnl_link_unregister_info(&bonding_info_ops);
    225 }
    226 
    227 /** @} */
    228