• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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