libnl 3.11.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#define BOND_HAS_HASHING_TYPE (1 << 2)
28#define BOND_HAS_MIIMON (1 << 3)
29#define BOND_HAS_MIN_LINKS (1 << 4)
30
31struct bond_info {
32 uint32_t ce_mask; /* to support attr macros */
33 uint8_t bn_mode;
34 uint8_t hashing_type;
35 uint32_t ifindex;
36 uint32_t miimon;
37 uint32_t min_links;
38};
39
40static int bond_info_alloc(struct rtnl_link *link)
41{
42 struct bond_info *bn;
43
44 if (link->l_info)
45 memset(link->l_info, 0, sizeof(*bn));
46 else {
47 bn = calloc(1, sizeof(*bn));
48 if (!bn)
49 return -NLE_NOMEM;
50
51 link->l_info = bn;
52 }
53
54 return 0;
55}
56
57static struct nla_policy bonding_nl_policy[IFLA_BOND_MAX + 1] = {
58 [IFLA_BOND_MODE] = { .type = NLA_U8 },
59 [IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 },
60 [IFLA_BOND_MIIMON] = { .type = NLA_U32 },
61 [IFLA_BOND_XMIT_HASH_POLICY] = { .type = NLA_U8 },
62 [IFLA_BOND_MIN_LINKS] = { .type = NLA_U32 },
63};
64
65static int bond_info_parse(struct rtnl_link *link, struct nlattr *data,
66 struct nlattr *xstats)
67{
68 struct nlattr *tb[IFLA_BOND_MAX + 1];
69 struct bond_info *bn;
70 int err;
71
72 err = nla_parse_nested(tb, IFLA_BOND_MAX, data, bonding_nl_policy);
73 if (err < 0)
74 return err;
75
76 err = bond_info_alloc(link);
77 if (err < 0)
78 return err;
79
80 bn = link->l_info;
81
82 if (tb[IFLA_BOND_MODE]) {
83 bn->bn_mode = nla_get_u8(tb[IFLA_BOND_MODE]);
84 bn->ce_mask |= BOND_HAS_MODE;
85 }
86
87 if (tb[IFLA_BOND_ACTIVE_SLAVE]) {
88 bn->ifindex = nla_get_u32(tb[IFLA_BOND_ACTIVE_SLAVE]);
89 bn->ce_mask |= BOND_HAS_ACTIVE_SLAVE;
90 }
91
92 if (tb[IFLA_BOND_MIIMON]) {
93 bn->hashing_type = nla_get_u32(tb[IFLA_BOND_MIIMON]);
94 bn->ce_mask |= BOND_HAS_MIIMON;
95 }
96
97 if (tb[IFLA_BOND_XMIT_HASH_POLICY]) {
98 bn->hashing_type = nla_get_u8(tb[IFLA_BOND_XMIT_HASH_POLICY]);
99 bn->ce_mask |= BOND_HAS_HASHING_TYPE;
100 }
101
102 if (tb[IFLA_BOND_MIN_LINKS]) {
103 bn->hashing_type = nla_get_u32(tb[IFLA_BOND_MIN_LINKS]);
104 bn->ce_mask |= BOND_HAS_MIN_LINKS;
105 }
106
107 return 0;
108}
109
110static void bond_info_free(struct rtnl_link *link)
111{
112 _nl_clear_free(&link->l_info);
113}
114
115static int bond_info_clone(struct rtnl_link *dst, struct rtnl_link *src)
116{
117 struct bond_info *bond_dst, *bond_src = src->l_info;
118 int err;
119
120 _nl_assert(bond_src);
121
122 err = bond_info_alloc(dst);
123 if (err)
124 return err;
125
126 bond_dst = dst->l_info;
127
128 _nl_assert(bond_dst);
129
130 *bond_dst = *bond_src;
131
132 return 0;
133}
134
135static int bond_put_attrs(struct nl_msg *msg, struct rtnl_link *link)
136{
137 struct bond_info *bn = link->l_info;
138 struct nlattr *data;
139
140 data = nla_nest_start(msg, IFLA_INFO_DATA);
141 if (!data)
142 return -NLE_MSGSIZE;
143 if (bn->ce_mask & BOND_HAS_MODE)
144 NLA_PUT_U8(msg, IFLA_BOND_MODE, bn->bn_mode);
145
146 if (bn->ce_mask & BOND_HAS_ACTIVE_SLAVE)
147 NLA_PUT_U32(msg, IFLA_BOND_ACTIVE_SLAVE, bn->ifindex);
148
149 if (bn->ce_mask & BOND_HAS_HASHING_TYPE)
150 NLA_PUT_U8(msg, IFLA_BOND_XMIT_HASH_POLICY, bn->hashing_type);
151
152 if (bn->ce_mask & BOND_HAS_MIIMON)
153 NLA_PUT_U32(msg, IFLA_BOND_MIIMON, bn->miimon);
154
155 if (bn->ce_mask & BOND_HAS_MIN_LINKS)
156 NLA_PUT_U32(msg, IFLA_BOND_MIN_LINKS, bn->min_links);
157
158 nla_nest_end(msg, data);
159 return 0;
160
161nla_put_failure:
162 nla_nest_cancel(msg, data);
163 return -NLE_MSGSIZE;
164}
165
166static int bond_info_compare(struct rtnl_link *link_a, struct rtnl_link *link_b,
167 int flags)
168{
169 struct bond_info *a = link_a->l_info;
170 struct bond_info *b = link_b->l_info;
171 uint32_t attrs = flags & LOOSE_COMPARISON ? b->ce_mask : ~0u;
172 int diff = 0;
173
174#define _DIFF(ATTR, EXPR) ATTR_DIFF(attrs, ATTR, a, b, EXPR)
175 diff |= _DIFF(BOND_HAS_MODE, a->bn_mode != b->bn_mode);
176 diff |= _DIFF(BOND_HAS_ACTIVE_SLAVE, a->ifindex != b->ifindex);
177 diff |= _DIFF(BOND_HAS_HASHING_TYPE,
178 a->hashing_type != b->hashing_type);
179 diff |= _DIFF(BOND_HAS_MIIMON, a->miimon != b->miimon);
180 diff |= _DIFF(BOND_HAS_MIN_LINKS, a->min_links != b->min_links);
181#undef _DIFF
182
183 return diff;
184}
185
186static struct rtnl_link_info_ops bonding_info_ops = {
187 .io_name = "bond",
188 .io_alloc = bond_info_alloc,
189 .io_parse = bond_info_parse,
190 .io_clone = bond_info_clone,
191 .io_put_attrs = bond_put_attrs,
192 .io_free = bond_info_free,
193 .io_compare = bond_info_compare,
194};
195
196#define IS_BOND_INFO_ASSERT(link) \
197 do { \
198 if (link->l_info_ops != &bonding_info_ops) { \
199 APPBUG("Link is not a bond link. Set type \"bond\" first."); \
200 } \
201 } while (0)
202
203/**
204 * Set active slave for bond
205 * @arg link Link object of type bond
206 * @arg active ifindex of active slave to set
207 *
208 * @return void
209 */
210void rtnl_link_bond_set_activeslave(struct rtnl_link *link, int active_slave)
211{
212 struct bond_info *bn = link->l_info;
213
214 IS_BOND_INFO_ASSERT(link);
215
216 bn->ifindex = active_slave;
217
218 bn->ce_mask |= BOND_HAS_ACTIVE_SLAVE;
219}
220
221/**
222 * Get active slave for bond
223 * @arg link Link object of type bond
224 * @arg active_slave Output argument
225 *
226 * @return Zero on success, otherwise a negative error code.
227 * @retval -NLE_NOATTR
228 * @retval -NLE_INVAL
229 */
230int rtnl_link_bond_get_activeslave(struct rtnl_link *link, int *active_slave)
231{
232 struct bond_info *bn = link->l_info;
233
234 IS_BOND_INFO_ASSERT(link);
235
236 if (!(bn->ce_mask & BOND_HAS_ACTIVE_SLAVE))
237 return -NLE_NOATTR;
238
239 if (!active_slave)
240 return -NLE_INVAL;
241
242 *active_slave = bn->ifindex;
243
244 return 0;
245}
246
247/**
248 * Set bond mode
249 * @arg link Link object of type bond
250 * @arg mode bond mode to set
251 *
252 * @return void
253 */
254void rtnl_link_bond_set_mode(struct rtnl_link *link, uint8_t mode)
255{
256 struct bond_info *bn = link->l_info;
257
258 IS_BOND_INFO_ASSERT(link);
259
260 bn->bn_mode = mode;
261
262 bn->ce_mask |= BOND_HAS_MODE;
263}
264
265/**
266 * Get bond mode
267 * @arg link Link object of type bond
268 * @arg mode Output argument
269 *
270 * @return Zero on success, otherwise a negative error code.
271 * @retval -NLE_NOATTR
272 * @retval -NLE_INVAL
273 */
274int rtnl_link_bond_get_mode(struct rtnl_link *link, uint8_t *mode)
275{
276 struct bond_info *bn = link->l_info;
277
278 IS_BOND_INFO_ASSERT(link);
279
280 if (!(bn->ce_mask & BOND_HAS_MODE))
281 return -NLE_NOATTR;
282
283 if (!mode)
284 return -NLE_INVAL;
285
286 *mode = bn->bn_mode;
287
288 return 0;
289}
290
291/**
292 * Set hashing type
293 * @arg link Link object of type bond
294 * @arg type bond hashing type to set
295 *
296 * @return void
297 */
298void rtnl_link_bond_set_hashing_type(struct rtnl_link *link, uint8_t type)
299{
300 struct bond_info *bn = link->l_info;
301
302 IS_BOND_INFO_ASSERT(link);
303
304 bn->hashing_type = type;
305
306 bn->ce_mask |= BOND_HAS_HASHING_TYPE;
307}
308
309/**
310 * Get hashing type
311 * @arg link Link object of type bond
312 * @arg type Output argument
313 *
314 * @return Zero on success, otherwise a negative error code.
315 * @retval -NLE_NOATTR
316 * @retval -NLE_INVAL
317 */
318int rtnl_link_bond_get_hashing_type(struct rtnl_link *link, uint8_t *type)
319{
320 struct bond_info *bn = link->l_info;
321
322 IS_BOND_INFO_ASSERT(link);
323
324 if (!(bn->ce_mask & BOND_HAS_HASHING_TYPE))
325 return -NLE_NOATTR;
326
327 if (!type)
328 return -NLE_INVAL;
329
330 *type = bn->hashing_type;
331
332 return 0;
333}
334
335/**
336 * Set MII monitoring interval
337 * @arg link Link object of type bond
338 * @arg miimon interval in milliseconds
339 *
340 * @return void
341 */
342void rtnl_link_bond_set_miimon(struct rtnl_link *link, uint32_t miimon)
343{
344 struct bond_info *bn = link->l_info;
345
346 IS_BOND_INFO_ASSERT(link);
347
348 bn->miimon = miimon;
349
350 bn->ce_mask |= BOND_HAS_MIIMON;
351}
352
353/**
354 * Get MII monitoring interval
355 * @arg link Link object of type bond
356 * @arg miimon Output argument
357 *
358 * @return Zero on success, otherwise a negative error code.
359 * @retval -NLE_NOATTR
360 * @retval -NLE_INVAL
361 */
362int rtnl_link_bond_get_miimon(struct rtnl_link *link, uint32_t *miimon)
363{
364 struct bond_info *bn = link->l_info;
365
366 IS_BOND_INFO_ASSERT(link);
367
368 if (!(bn->ce_mask & BOND_HAS_MIIMON))
369 return -NLE_NOATTR;
370
371 if (!miimon)
372 return -NLE_INVAL;
373
374 *miimon = bn->miimon;
375
376 return 0;
377}
378
379/**
380 * Set the minimum number of member ports that must be up before
381 * marking the bond device as up
382 * @arg link Link object of type bond
383 * @arg min_links Number of links
384 *
385 * @return void
386 */
387void rtnl_link_bond_set_min_links(struct rtnl_link *link, uint32_t min_links)
388{
389 struct bond_info *bn = link->l_info;
390
391 IS_BOND_INFO_ASSERT(link);
392
393 bn->min_links = min_links;
394
395 bn->ce_mask |= BOND_HAS_MIN_LINKS;
396}
397/**
398 * Get the minimum number of member ports that must be up before
399 * marking the bond device as up
400 * @arg link Link object of type bond
401 * @arg min_links Output argument.
402 *
403 * @return Zero on success, otherwise a negative error code.
404 * @retval -NLE_NOATTR
405 * @retval -NLE_INVAL
406 */
407int rtnl_link_bond_get_min_links(struct rtnl_link *link, uint32_t *min_links)
408{
409 struct bond_info *bn = link->l_info;
410
411 IS_BOND_INFO_ASSERT(link);
412
413 if (!(bn->ce_mask & BOND_HAS_MIN_LINKS))
414 return -NLE_NOATTR;
415
416 if (!min_links)
417 return -NLE_INVAL;
418
419 *min_links = bn->min_links;
420
421 return 0;
422}
423
424/**
425 * Allocate link object of type bond
426 *
427 * @return Allocated link object or NULL.
428 */
430{
431 struct rtnl_link *link;
432
433 if (!(link = rtnl_link_alloc()))
434 return NULL;
435
436 if (rtnl_link_set_type(link, "bond") < 0) {
437 rtnl_link_put(link);
438 return NULL;
439 }
440
441 return link;
442}
443
444/**
445 * Create a new kernel bonding device
446 * @arg sock netlink socket
447 * @arg name name of bonding device or NULL
448 * @arg opts bonding options (currently unused)
449 *
450 * Creates a new bonding device in the kernel. If no name is
451 * provided, the kernel will automatically pick a name of the
452 * form "type%d" (e.g. bond0, vlan1, etc.)
453 *
454 * The \a opts argument is currently unused. In the future, it
455 * may be used to carry additional bonding options to be set
456 * when creating the bonding device.
457 *
458 * @note When letting the kernel assign a name, it will become
459 * difficult to retrieve the interface afterwards because
460 * you have to guess the name the kernel has chosen. It is
461 * therefore not recommended to not provide a device name.
462 *
463 * @see rtnl_link_bond_enslave()
464 * @see rtnl_link_bond_release()
465 *
466 * @return 0 on success or a negative error code
467 */
468int rtnl_link_bond_add(struct nl_sock *sock, const char *name,
469 struct rtnl_link *opts)
470{
471 struct rtnl_link *link;
472 int err;
473
474 if (!(link = rtnl_link_bond_alloc()))
475 return -NLE_NOMEM;
476
477 if (!name && opts)
478 name = rtnl_link_get_name(opts);
479
480 if (name)
481 rtnl_link_set_name(link, name);
482
483 err = rtnl_link_add(sock, link, NLM_F_CREATE);
484
485 rtnl_link_put(link);
486
487 return err;
488}
489
490/**
491 * Add a link to a bond (enslave)
492 * @arg sock netlink socket
493 * @arg master ifindex of bonding master
494 * @arg slave ifindex of slave link to add to bond
495 *
496 * This function is identical to rtnl_link_bond_enslave() except that
497 * it takes interface indices instead of rtnl_link objcets.
498 *
499 * @see rtnl_link_bond_enslave()
500 *
501 * @return 0 on success or a negative error code.
502 */
503int rtnl_link_bond_enslave_ifindex(struct nl_sock *sock, int master,
504 int slave)
505{
506 struct rtnl_link *link;
507 int err;
508
509 if (!(link = rtnl_link_bond_alloc()))
510 return -NLE_NOMEM;
511
512 rtnl_link_set_ifindex(link, slave);
513 rtnl_link_set_master(link, master);
514
515 if ((err = rtnl_link_change(sock, link, link, 0)) < 0)
516 goto errout;
517
518 rtnl_link_put(link);
519
520 /*
521 * Due to the kernel not signaling whether this opertion is
522 * supported or not, we will retrieve the attribute to see if the
523 * request was successful. If the master assigned remains unchanged
524 * we will return NLE_OPNOTSUPP to allow performing backwards
525 * compatibility of some sort.
526 */
527 if ((err = rtnl_link_get_kernel(sock, slave, NULL, &link)) < 0)
528 return err;
529
530 if (rtnl_link_get_master(link) != master)
531 err = -NLE_OPNOTSUPP;
532
533errout:
534 rtnl_link_put(link);
535
536 return err;
537}
538
539/**
540 * Add a link to a bond (enslave)
541 * @arg sock netlink socket
542 * @arg master bonding master
543 * @arg slave slave link to add to bond
544 *
545 * Constructs a RTM_NEWLINK or RTM_SETLINK message adding the slave to
546 * the master and sends the request via the specified netlink socket.
547 *
548 * @note The feature of enslaving/releasing via netlink has only been added
549 * recently to the kernel (Feb 2011). Also, the kernel does not signal
550 * if the operation is not supported. Therefore this function will
551 * verify if the master assignment has changed and will return
552 * -NLE_OPNOTSUPP if it did not.
553 *
554 * @see rtnl_link_bond_enslave_ifindex()
555 * @see rtnl_link_bond_release()
556 *
557 * @return 0 on success or a negative error code.
558 */
559int rtnl_link_bond_enslave(struct nl_sock *sock, struct rtnl_link *master,
560 struct rtnl_link *slave)
561{
563 rtnl_link_get_ifindex(master),
564 rtnl_link_get_ifindex(slave));
565}
566
567/**
568 * Release a link from a bond
569 * @arg sock netlink socket
570 * @arg slave slave link to be released
571 *
572 * This function is identical to rtnl_link_bond_release() except that
573 * it takes an interface index instead of a rtnl_link object.
574 *
575 * @see rtnl_link_bond_release()
576 *
577 * @return 0 on success or a negative error code.
578 */
579int rtnl_link_bond_release_ifindex(struct nl_sock *sock, int slave)
580{
581 return rtnl_link_bond_enslave_ifindex(sock, 0, slave);
582}
583
584/**
585 * Release a link from a bond
586 * @arg sock netlink socket
587 * @arg slave slave link to be released
588 *
589 * Constructs a RTM_NEWLINK or RTM_SETLINK message releasing the slave from
590 * its master and sends the request via the specified netlink socket.
591 *
592 * @note The feature of enslaving/releasing via netlink has only been added
593 * recently to the kernel (Feb 2011). Also, the kernel does not signal
594 * if the operation is not supported. Therefore this function will
595 * verify if the master assignment has changed and will return
596 * -NLE_OPNOTSUPP if it did not.
597 *
598 * @see rtnl_link_bond_release_ifindex()
599 * @see rtnl_link_bond_enslave()
600 *
601 * @return 0 on success or a negative error code.
602 */
603int rtnl_link_bond_release(struct nl_sock *sock, struct rtnl_link *slave)
604{
606 rtnl_link_get_ifindex(slave));
607}
608
609static void _nl_init bonding_init(void)
610{
611 rtnl_link_register_info(&bonding_info_ops);
612}
613
614static void _nl_exit bonding_exit(void)
615{
616 rtnl_link_unregister_info(&bonding_info_ops);
617}
618
619/** @} */
uint32_t nla_get_u32(const struct nlattr *nla)
Return payload of 32 bit integer attribute.
Definition attr.c:714
#define NLA_PUT_U8(msg, attrtype, value)
Add 8 bit integer attribute to netlink message.
Definition attr.h:201
#define NLA_PUT_U32(msg, attrtype, value)
Add 32 bit integer attribute to netlink message.
Definition attr.h:237
uint8_t nla_get_u8(const struct nlattr *nla)
Return value of 8 bit integer attribute.
Definition attr.c:614
struct nlattr * nla_nest_start(struct nl_msg *msg, int attrtype)
Start a new level of nested attributes.
Definition attr.c:974
int nla_parse_nested(struct nlattr *tb[], int maxtype, struct nlattr *nla, const struct nla_policy *policy)
Create attribute index based on nested attribute.
Definition attr.c:1101
void nla_nest_cancel(struct nl_msg *msg, const struct nlattr *attr)
Cancel the addition of a nested attribute.
Definition attr.c:1066
int nla_nest_end(struct nl_msg *msg, struct nlattr *start)
Finalize nesting of attributes.
Definition attr.c:1037
@ NLA_U8
8 bit integer
Definition attr.h:35
@ NLA_U32
32 bit integer
Definition attr.h:37
void rtnl_link_bond_set_mode(struct rtnl_link *link, uint8_t mode)
Set bond mode.
Definition bonding.c:254
void rtnl_link_bond_set_min_links(struct rtnl_link *link, uint32_t min_links)
Set the minimum number of member ports that must be up before marking the bond device as up.
Definition bonding.c:387
int rtnl_link_bond_get_min_links(struct rtnl_link *link, uint32_t *min_links)
Get the minimum number of member ports that must be up before marking the bond device as up.
Definition bonding.c:407
int rtnl_link_bond_get_miimon(struct rtnl_link *link, uint32_t *miimon)
Get MII monitoring interval.
Definition bonding.c:362
void rtnl_link_bond_set_activeslave(struct rtnl_link *link, int active_slave)
Set active slave for bond.
Definition bonding.c:210
int rtnl_link_bond_get_mode(struct rtnl_link *link, uint8_t *mode)
Get bond mode.
Definition bonding.c:274
int rtnl_link_bond_get_hashing_type(struct rtnl_link *link, uint8_t *type)
Get hashing type.
Definition bonding.c:318
int rtnl_link_bond_enslave_ifindex(struct nl_sock *sock, int master, int slave)
Add a link to a bond (enslave)
Definition bonding.c:503
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:468
struct rtnl_link * rtnl_link_bond_alloc(void)
Allocate link object of type bond.
Definition bonding.c:429
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:559
int rtnl_link_bond_release(struct nl_sock *sock, struct rtnl_link *slave)
Release a link from a bond.
Definition bonding.c:603
void rtnl_link_bond_set_hashing_type(struct rtnl_link *link, uint8_t type)
Set hashing type.
Definition bonding.c:298
int rtnl_link_bond_release_ifindex(struct nl_sock *sock, int slave)
Release a link from a bond.
Definition bonding.c:579
void rtnl_link_bond_set_miimon(struct rtnl_link *link, uint32_t miimon)
Set MII monitoring interval.
Definition bonding.c:342
int rtnl_link_bond_get_activeslave(struct rtnl_link *link, int *active_slave)
Get active slave for bond.
Definition bonding.c:230
Attribute validation policy.
Definition attr.h:66
uint16_t type
Type of attribute or NLA_UNSPEC.
Definition attr.h:68