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@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 */
rtnl_link_bond_alloc(void)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 */
rtnl_link_bond_add(struct nl_sock * sock,const char * name,struct rtnl_link * opts)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 */
rtnl_link_bond_enslave_ifindex(struct nl_sock * sock,int master,int slave)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 */
rtnl_link_bond_enslave(struct nl_sock * sock,struct rtnl_link * master,struct rtnl_link * slave)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 */
rtnl_link_bond_release_ifindex(struct nl_sock * sock,int slave)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 */
rtnl_link_bond_release(struct nl_sock * sock,struct rtnl_link * slave)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
bonding_init(void)217 static void __init bonding_init(void)
218 {
219 rtnl_link_register_info(&bonding_info_ops);
220 }
221
bonding_exit(void)222 static void __exit bonding_exit(void)
223 {
224 rtnl_link_unregister_info(&bonding_info_ops);
225 }
226
227 /** @} */
228