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