libnl 3.8.0
bonding.c
1/* SPDX-License-Identifier: LGPL-2.1-only */
2/*
3 * Copyright (c) 2011-2013 Thomas Graf <tgraf@suug.ch>
4 */
5
6/**
7 * @ingroup link
8 * @defgroup bonding Bonding
9 *
10 * @details
11 * \b Link Type Name: "bond"
12 *
13 * @route_doc{link_bonding, Bonding Documentation}
14 * @{
15 */
16
17#include "nl-default.h"
18
19#include <netlink/netlink.h>
20#include <netlink/route/link/bonding.h>
21
22#include "nl-route.h"
23#include "link-api.h"
24
25#define BOND_HAS_MODE (1 << 0)
26#define BOND_HAS_ACTIVE_SLAVE (1 << 1)
27
28struct bond_info {
29 uint8_t bn_mode;
30 uint32_t ifindex;
31 uint32_t bn_mask;
32};
33
34static int bond_info_alloc(struct rtnl_link *link)
35{
36 struct bond_info *bn;
37
38 if (link->l_info)
39 memset(link->l_info, 0, sizeof(*bn));
40 else {
41 bn = calloc(1, sizeof(*bn));
42 if (!bn)
43 return -NLE_NOMEM;
44
45 link->l_info = bn;
46 }
47
48 return 0;
49}
50
51static void bond_info_free(struct rtnl_link *link)
52{
53 _nl_clear_free(&link->l_info);
54}
55
56static int bond_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
57{
58 struct bond_info *bn = link->l_info;
59 struct nlattr *data;
60
61 data = nla_nest_start(msg, IFLA_INFO_DATA);
62 if (!data)
63 return -NLE_MSGSIZE;
64 if (bn->bn_mask & BOND_HAS_MODE)
65 NLA_PUT_U8(msg, IFLA_BOND_MODE, bn->bn_mode);
66
67 if (bn->bn_mask & BOND_HAS_ACTIVE_SLAVE)
68 NLA_PUT_U32(msg, IFLA_BOND_ACTIVE_SLAVE, bn->ifindex);
69
70 nla_nest_end(msg, data);
71 return 0;
72
73nla_put_failure:
74 nla_nest_cancel(msg, data);
75 return -NLE_MSGSIZE;
76}
77
78static struct rtnl_link_info_ops bonding_info_ops = {
79 .io_name = "bond",
80 .io_alloc = bond_info_alloc,
81 .io_put_attrs = bond_put_attrs,
82 .io_free = bond_info_free,
83};
84
85#define IS_BOND_INFO_ASSERT(link) \
86 do { \
87 if (link->l_info_ops != &bonding_info_ops) { \
88 APPBUG("Link is not a bond link. Set type \"bond\" first."); \
89 } \
90 } while (0)
91
92/**
93 * Set active slave for bond
94 * @arg link Link object of type bond
95 * @arg active ifindex of active slave to set
96 *
97 * @return void
98 */
99void rtnl_link_bond_set_activeslave(struct rtnl_link *link, int active_slave)
100{
101 struct bond_info *bn = link->l_info;
102
103 IS_BOND_INFO_ASSERT(link);
104
105 bn->ifindex = active_slave;
106
107 bn->bn_mask |= BOND_HAS_ACTIVE_SLAVE;
108}
109
110/**
111 * Set bond mode
112 * @arg link Link object of type bond
113 * @arg mode bond mode to set
114 *
115 * @return void
116 */
117void rtnl_link_bond_set_mode(struct rtnl_link *link, uint8_t mode)
118{
119 struct bond_info *bn = link->l_info;
120
121 IS_BOND_INFO_ASSERT(link);
122
123 bn->bn_mode = mode;
124
125 bn->bn_mask |= BOND_HAS_MODE;
126}
127
128/**
129 * Allocate link object of type bond
130 *
131 * @return Allocated link object or NULL.
132 */
134{
135 struct rtnl_link *link;
136
137 if (!(link = rtnl_link_alloc()))
138 return NULL;
139
140 if (rtnl_link_set_type(link, "bond") < 0) {
141 rtnl_link_put(link);
142 return NULL;
143 }
144
145 return link;
146}
147
148/**
149 * Create a new kernel bonding device
150 * @arg sock netlink socket
151 * @arg name name of bonding device or NULL
152 * @arg opts bonding options (currently unused)
153 *
154 * Creates a new bonding device in the kernel. If no name is
155 * provided, the kernel will automatically pick a name of the
156 * form "type%d" (e.g. bond0, vlan1, etc.)
157 *
158 * The \a opts argument is currently unused. In the future, it
159 * may be used to carry additional bonding options to be set
160 * when creating the bonding device.
161 *
162 * @note When letting the kernel assign a name, it will become
163 * difficult to retrieve the interface afterwards because
164 * you have to guess the name the kernel has chosen. It is
165 * therefore not recommended to not provide a device name.
166 *
167 * @see rtnl_link_bond_enslave()
168 * @see rtnl_link_bond_release()
169 *
170 * @return 0 on success or a negative error code
171 */
172int rtnl_link_bond_add(struct nl_sock *sock, const char *name,
173 struct rtnl_link *opts)
174{
175 struct rtnl_link *link;
176 int err;
177
178 if (!(link = rtnl_link_bond_alloc()))
179 return -NLE_NOMEM;
180
181 if (!name && opts)
182 name = rtnl_link_get_name(opts);
183
184 if (name)
185 rtnl_link_set_name(link, name);
186
187 err = rtnl_link_add(sock, link, NLM_F_CREATE);
188
189 rtnl_link_put(link);
190
191 return err;
192}
193
194/**
195 * Add a link to a bond (enslave)
196 * @arg sock netlink socket
197 * @arg master ifindex of bonding master
198 * @arg slave ifindex of slave link to add to bond
199 *
200 * This function is identical to rtnl_link_bond_enslave() except that
201 * it takes interface indices instead of rtnl_link objcets.
202 *
203 * @see rtnl_link_bond_enslave()
204 *
205 * @return 0 on success or a negative error code.
206 */
207int rtnl_link_bond_enslave_ifindex(struct nl_sock *sock, int master,
208 int slave)
209{
210 struct rtnl_link *link;
211 int err;
212
213 if (!(link = rtnl_link_bond_alloc()))
214 return -NLE_NOMEM;
215
216 rtnl_link_set_ifindex(link, slave);
217 rtnl_link_set_master(link, master);
218
219 if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
220 goto errout;
221
222 rtnl_link_put(link);
223
224 /*
225 * Due to the kernel not signaling whether this opertion is
226 * supported or not, we will retrieve the attribute to see if the
227 * request was successful. If the master assigned remains unchanged
228 * we will return NLE_OPNOTSUPP to allow performing backwards
229 * compatibility of some sort.
230 */
231 if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
232 return err;
233
234 if (rtnl_link_get_master(link) != master)
235 err = -NLE_OPNOTSUPP;
236
237errout:
238 rtnl_link_put(link);
239
240 return err;
241}
242
243/**
244 * Add a link to a bond (enslave)
245 * @arg sock netlink socket
246 * @arg master bonding master
247 * @arg slave slave link to add to bond
248 *
249 * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to
250 * the master and sends the request via the specified netlink socket.
251 *
252 * @note The feature of enslaving/releasing via netlink has only been added
253 * recently to the kernel (Feb 2011). Also, the kernel does not signal
254 * if the operation is not supported. Therefore this function will
255 * verify if the master assignment has changed and will return
256 * -NLE_OPNOTSUPP if it did not.
257 *
258 * @see rtnl_link_bond_enslave_ifindex()
259 * @see rtnl_link_bond_release()
260 *
261 * @return 0 on success or a negative error code.
262 */
263int rtnl_link_bond_enslave(struct nl_sock *sock, struct rtnl_link *master,
264 struct rtnl_link *slave)
265{
267 rtnl_link_get_ifindex(master),
268 rtnl_link_get_ifindex(slave));
269}
270
271/**
272 * Release a link from a bond
273 * @arg sock netlink socket
274 * @arg slave slave link to be released
275 *
276 * This function is identical to rtnl_link_bond_release() except that
277 * it takes an interface index instead of a rtnl_link object.
278 *
279 * @see rtnl_link_bond_release()
280 *
281 * @return 0 on success or a negative error code.
282 */
283int rtnl_link_bond_release_ifindex(struct nl_sock *sock, int slave)
284{
285 return rtnl_link_bond_enslave_ifindex(sock, 0, slave);
286}
287
288/**
289 * Release a link from a bond
290 * @arg sock netlink socket
291 * @arg slave slave link to be released
292 *
293 * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from
294 * its master and sends the request via the specified netlink socket.
295 *
296 * @note The feature of enslaving/releasing via netlink has only been added
297 * recently to the kernel (Feb 2011). Also, the kernel does not signal
298 * if the operation is not supported. Therefore this function will
299 * verify if the master assignment has changed and will return
300 * -NLE_OPNOTSUPP if it did not.
301 *
302 * @see rtnl_link_bond_release_ifindex()
303 * @see rtnl_link_bond_enslave()
304 *
305 * @return 0 on success or a negative error code.
306 */
307int rtnl_link_bond_release(struct nl_sock *sock, struct rtnl_link *slave)
308{
310 rtnl_link_get_ifindex(slave));
311}
312
313static void _nl_init bonding_init(void)
314{
315 rtnl_link_register_info(&bonding_info_ops);
316}
317
318static void _nl_exit bonding_exit(void)
319{
320 rtnl_link_unregister_info(&bonding_info_ops);
321}
322
323/** @} */
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition: attr.h:194
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition: attr.h:230
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition: attr.c:906
void nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr)
Cancel the addition of a nested attribute.
Definition: attr.c:998
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition: attr.c:969
void rtnl_link_bond_set_mode(struct rtnl_link *link, uint8_t mode)
Set bond mode.
Definition: bonding.c:117
void rtnl_link_bond_set_activeslave(struct rtnl_link *link, int active_slave)
Set active slave for bond.
Definition: bonding.c:99
int rtnl_link_bond_enslave_ifindex(struct nl_sock *sock, int master, int slave)
Add a link to a bond (enslave)
Definition: bonding.c:207
int rtnl_link_bond_add(struct nl_sock *sock, const char *name, struct rtnl_link *opts)
Create a new kernel bonding device.
Definition: bonding.c:172
struct rtnl_link * rtnl_link_bond_alloc(void)
Allocate link object of type bond.
Definition: bonding.c:133
int rtnl_link_bond_enslave(struct nl_sock *sock, struct rtnl_link *master, struct rtnl_link *slave)
Add a link to a bond (enslave)
Definition: bonding.c:263
int rtnl_link_bond_release(struct nl_sock *sock, struct rtnl_link *slave)
Release a link from a bond.
Definition: bonding.c:307
int rtnl_link_bond_release_ifindex(struct nl_sock *sock, int slave)
Release a link from a bond.
Definition: bonding.c:283