blob: b361c674dc00718d294169457014358224d75116 [file] [log] [blame]
Jiri Pirko0a2a78c2013-10-18 17:43:33 +02001/*
2 * drivers/net/bond/bond_netlink.c - Netlink interface for bonding
3 * Copyright (c) 2013 Jiri Pirko <jiri@resnulli.us>
sfeldma@cumulusnetworks.comeecdaa62013-12-12 14:09:55 -08004 * Copyright (c) 2013 Scott Feldman <sfeldma@cumulusnetworks.com>
Jiri Pirko0a2a78c2013-10-18 17:43:33 +02005 *
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
10 */
11
12#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
13
14#include <linux/module.h>
15#include <linux/errno.h>
16#include <linux/netdevice.h>
17#include <linux/etherdevice.h>
18#include <linux/if_link.h>
19#include <linux/if_ether.h>
20#include <net/netlink.h>
21#include <net/rtnetlink.h>
22#include "bonding.h"
23
Jiri Pirko90af2312013-10-18 17:43:38 +020024static const struct nla_policy bond_policy[IFLA_BOND_MAX + 1] = {
25 [IFLA_BOND_MODE] = { .type = NLA_U8 },
Jiri Pirkoec76aa42013-10-18 17:43:39 +020026 [IFLA_BOND_ACTIVE_SLAVE] = { .type = NLA_U32 },
sfeldma@cumulusnetworks.comeecdaa62013-12-12 14:09:55 -080027 [IFLA_BOND_MIIMON] = { .type = NLA_U32 },
sfeldma@cumulusnetworks.com25852e22013-12-12 14:10:02 -080028 [IFLA_BOND_UPDELAY] = { .type = NLA_U32 },
sfeldma@cumulusnetworks.comc7461f92013-12-12 14:10:09 -080029 [IFLA_BOND_DOWNDELAY] = { .type = NLA_U32 },
sfeldma@cumulusnetworks.com9f53e142013-12-12 14:10:16 -080030 [IFLA_BOND_USE_CARRIER] = { .type = NLA_U8 },
sfeldma@cumulusnetworks.com06151db2013-12-12 14:10:24 -080031 [IFLA_BOND_ARP_INTERVAL] = { .type = NLA_U32 },
sfeldma@cumulusnetworks.com7f28fa12013-12-12 14:10:31 -080032 [IFLA_BOND_ARP_IP_TARGET] = { .type = NLA_NESTED },
sfeldma@cumulusnetworks.com29c49482013-12-12 14:10:38 -080033 [IFLA_BOND_ARP_VALIDATE] = { .type = NLA_U32 },
sfeldma@cumulusnetworks.comd5c84252013-12-12 14:10:45 -080034 [IFLA_BOND_ARP_ALL_TARGETS] = { .type = NLA_U32 },
sfeldma@cumulusnetworks.com0a98a0d2013-12-15 16:41:51 -080035 [IFLA_BOND_PRIMARY] = { .type = NLA_U32 },
sfeldma@cumulusnetworks.com8a41ae42013-12-15 16:41:58 -080036 [IFLA_BOND_PRIMARY_RESELECT] = { .type = NLA_U8 },
Jiri Pirko90af2312013-10-18 17:43:38 +020037};
38
Jiri Pirko0a2a78c2013-10-18 17:43:33 +020039static int bond_validate(struct nlattr *tb[], struct nlattr *data[])
40{
41 if (tb[IFLA_ADDRESS]) {
42 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
43 return -EINVAL;
44 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
45 return -EADDRNOTAVAIL;
46 }
47 return 0;
48}
49
Jiri Pirko90af2312013-10-18 17:43:38 +020050static int bond_changelink(struct net_device *bond_dev,
51 struct nlattr *tb[], struct nlattr *data[])
52{
53 struct bonding *bond = netdev_priv(bond_dev);
sfeldma@cumulusnetworks.com06151db2013-12-12 14:10:24 -080054 int miimon = 0;
Jiri Pirko90af2312013-10-18 17:43:38 +020055 int err;
56
sfeldma@cumulusnetworks.comeecdaa62013-12-12 14:09:55 -080057 if (!data)
58 return 0;
59
60 if (data[IFLA_BOND_MODE]) {
Jiri Pirko90af2312013-10-18 17:43:38 +020061 int mode = nla_get_u8(data[IFLA_BOND_MODE]);
62
63 err = bond_option_mode_set(bond, mode);
64 if (err)
65 return err;
66 }
sfeldma@cumulusnetworks.comeecdaa62013-12-12 14:09:55 -080067 if (data[IFLA_BOND_ACTIVE_SLAVE]) {
Jiri Pirkoec76aa42013-10-18 17:43:39 +020068 int ifindex = nla_get_u32(data[IFLA_BOND_ACTIVE_SLAVE]);
69 struct net_device *slave_dev;
70
71 if (ifindex == 0) {
72 slave_dev = NULL;
73 } else {
74 slave_dev = __dev_get_by_index(dev_net(bond_dev),
75 ifindex);
76 if (!slave_dev)
77 return -ENODEV;
78 }
79 err = bond_option_active_slave_set(bond, slave_dev);
80 if (err)
81 return err;
82 }
sfeldma@cumulusnetworks.comeecdaa62013-12-12 14:09:55 -080083 if (data[IFLA_BOND_MIIMON]) {
sfeldma@cumulusnetworks.com06151db2013-12-12 14:10:24 -080084 miimon = nla_get_u32(data[IFLA_BOND_MIIMON]);
sfeldma@cumulusnetworks.comeecdaa62013-12-12 14:09:55 -080085
86 err = bond_option_miimon_set(bond, miimon);
87 if (err)
88 return err;
89 }
sfeldma@cumulusnetworks.com25852e22013-12-12 14:10:02 -080090 if (data[IFLA_BOND_UPDELAY]) {
91 int updelay = nla_get_u32(data[IFLA_BOND_UPDELAY]);
92
93 err = bond_option_updelay_set(bond, updelay);
94 if (err)
95 return err;
96 }
sfeldma@cumulusnetworks.comc7461f92013-12-12 14:10:09 -080097 if (data[IFLA_BOND_DOWNDELAY]) {
98 int downdelay = nla_get_u32(data[IFLA_BOND_DOWNDELAY]);
99
100 err = bond_option_downdelay_set(bond, downdelay);
101 if (err)
102 return err;
103 }
sfeldma@cumulusnetworks.com9f53e142013-12-12 14:10:16 -0800104 if (data[IFLA_BOND_USE_CARRIER]) {
105 int use_carrier = nla_get_u8(data[IFLA_BOND_USE_CARRIER]);
106
107 err = bond_option_use_carrier_set(bond, use_carrier);
108 if (err)
109 return err;
110 }
sfeldma@cumulusnetworks.com06151db2013-12-12 14:10:24 -0800111 if (data[IFLA_BOND_ARP_INTERVAL]) {
112 int arp_interval = nla_get_u32(data[IFLA_BOND_ARP_INTERVAL]);
113
114 if (arp_interval && miimon) {
115 pr_err("%s: ARP monitoring cannot be used with MII monitoring.\n",
116 bond->dev->name);
117 return -EINVAL;
118 }
119
120 err = bond_option_arp_interval_set(bond, arp_interval);
121 if (err)
122 return err;
123 }
sfeldma@cumulusnetworks.com7f28fa12013-12-12 14:10:31 -0800124 if (data[IFLA_BOND_ARP_IP_TARGET]) {
125 __be32 targets[BOND_MAX_ARP_TARGETS] = { 0, };
126 struct nlattr *attr;
127 int i = 0, rem;
128
129 nla_for_each_nested(attr, data[IFLA_BOND_ARP_IP_TARGET], rem) {
Jiri Pirkoe7ef9412013-12-14 12:32:10 +0100130 __be32 target = nla_get_be32(attr);
sfeldma@cumulusnetworks.com7f28fa12013-12-12 14:10:31 -0800131 targets[i++] = target;
132 }
133
134 err = bond_option_arp_ip_targets_set(bond, targets, i);
135 if (err)
136 return err;
137 }
sfeldma@cumulusnetworks.com29c49482013-12-12 14:10:38 -0800138 if (data[IFLA_BOND_ARP_VALIDATE]) {
139 int arp_validate = nla_get_u32(data[IFLA_BOND_ARP_VALIDATE]);
140
141 if (arp_validate && miimon) {
142 pr_err("%s: ARP validating cannot be used with MII monitoring.\n",
143 bond->dev->name);
144 return -EINVAL;
145 }
146
147 err = bond_option_arp_validate_set(bond, arp_validate);
148 if (err)
149 return err;
150 }
sfeldma@cumulusnetworks.comd5c84252013-12-12 14:10:45 -0800151 if (data[IFLA_BOND_ARP_ALL_TARGETS]) {
152 int arp_all_targets =
153 nla_get_u32(data[IFLA_BOND_ARP_ALL_TARGETS]);
154
155 err = bond_option_arp_all_targets_set(bond, arp_all_targets);
156 if (err)
157 return err;
158 }
sfeldma@cumulusnetworks.com0a98a0d2013-12-15 16:41:51 -0800159 if (data[IFLA_BOND_PRIMARY]) {
160 int ifindex = nla_get_u32(data[IFLA_BOND_PRIMARY]);
161 struct net_device *dev;
162 char *primary = "";
163
164 dev = __dev_get_by_index(dev_net(bond_dev), ifindex);
165 if (dev)
166 primary = dev->name;
167
168 err = bond_option_primary_set(bond, primary);
169 if (err)
170 return err;
171 }
sfeldma@cumulusnetworks.com8a41ae42013-12-15 16:41:58 -0800172 if (data[IFLA_BOND_PRIMARY_RESELECT]) {
173 int primary_reselect =
174 nla_get_u8(data[IFLA_BOND_PRIMARY_RESELECT]);
175
176 err = bond_option_primary_reselect_set(bond, primary_reselect);
177 if (err)
178 return err;
179 }
Jiri Pirko90af2312013-10-18 17:43:38 +0200180 return 0;
181}
182
183static int bond_newlink(struct net *src_net, struct net_device *bond_dev,
184 struct nlattr *tb[], struct nlattr *data[])
185{
186 int err;
187
188 err = bond_changelink(bond_dev, tb, data);
189 if (err < 0)
190 return err;
191
192 return register_netdevice(bond_dev);
193}
194
195static size_t bond_get_size(const struct net_device *bond_dev)
196{
Dan Carpentere1398622013-11-01 13:18:44 +0300197 return nla_total_size(sizeof(u8)) + /* IFLA_BOND_MODE */
sfeldma@cumulusnetworks.comeecdaa62013-12-12 14:09:55 -0800198 nla_total_size(sizeof(u32)) + /* IFLA_BOND_ACTIVE_SLAVE */
199 nla_total_size(sizeof(u32)) + /* IFLA_BOND_MIIMON */
sfeldma@cumulusnetworks.com25852e22013-12-12 14:10:02 -0800200 nla_total_size(sizeof(u32)) + /* IFLA_BOND_UPDELAY */
sfeldma@cumulusnetworks.comc7461f92013-12-12 14:10:09 -0800201 nla_total_size(sizeof(u32)) + /* IFLA_BOND_DOWNDELAY */
sfeldma@cumulusnetworks.com9f53e142013-12-12 14:10:16 -0800202 nla_total_size(sizeof(u8)) + /* IFLA_BOND_USE_CARRIER */
sfeldma@cumulusnetworks.com06151db2013-12-12 14:10:24 -0800203 nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_INTERVAL */
sfeldma@cumulusnetworks.com7f28fa12013-12-12 14:10:31 -0800204 /* IFLA_BOND_ARP_IP_TARGET */
205 nla_total_size(sizeof(u32)) * BOND_MAX_ARP_TARGETS +
sfeldma@cumulusnetworks.com29c49482013-12-12 14:10:38 -0800206 nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_VALIDATE */
sfeldma@cumulusnetworks.comd5c84252013-12-12 14:10:45 -0800207 nla_total_size(sizeof(u32)) + /* IFLA_BOND_ARP_ALL_TARGETS */
sfeldma@cumulusnetworks.com0a98a0d2013-12-15 16:41:51 -0800208 nla_total_size(sizeof(u32)) + /* IFLA_BOND_PRIMARY */
sfeldma@cumulusnetworks.com8a41ae42013-12-15 16:41:58 -0800209 nla_total_size(sizeof(u8)) + /* IFLA_BOND_PRIMARY_RESELECT */
sfeldma@cumulusnetworks.comeecdaa62013-12-12 14:09:55 -0800210 0;
Jiri Pirko90af2312013-10-18 17:43:38 +0200211}
212
213static int bond_fill_info(struct sk_buff *skb,
214 const struct net_device *bond_dev)
215{
216 struct bonding *bond = netdev_priv(bond_dev);
Jiri Pirkoec76aa42013-10-18 17:43:39 +0200217 struct net_device *slave_dev = bond_option_active_slave_get(bond);
sfeldma@cumulusnetworks.com7f28fa12013-12-12 14:10:31 -0800218 struct nlattr *targets;
219 int i, targets_added;
Jiri Pirko90af2312013-10-18 17:43:38 +0200220
sfeldma@cumulusnetworks.comeecdaa62013-12-12 14:09:55 -0800221 if (nla_put_u8(skb, IFLA_BOND_MODE, bond->params.mode))
Jiri Pirko90af2312013-10-18 17:43:38 +0200222 goto nla_put_failure;
sfeldma@cumulusnetworks.comeecdaa62013-12-12 14:09:55 -0800223
224 if (slave_dev &&
225 nla_put_u32(skb, IFLA_BOND_ACTIVE_SLAVE, slave_dev->ifindex))
226 goto nla_put_failure;
227
228 if (nla_put_u32(skb, IFLA_BOND_MIIMON, bond->params.miimon))
229 goto nla_put_failure;
230
sfeldma@cumulusnetworks.com25852e22013-12-12 14:10:02 -0800231 if (nla_put_u32(skb, IFLA_BOND_UPDELAY,
232 bond->params.updelay * bond->params.miimon))
233 goto nla_put_failure;
234
sfeldma@cumulusnetworks.comc7461f92013-12-12 14:10:09 -0800235 if (nla_put_u32(skb, IFLA_BOND_DOWNDELAY,
236 bond->params.downdelay * bond->params.miimon))
237 goto nla_put_failure;
238
sfeldma@cumulusnetworks.com9f53e142013-12-12 14:10:16 -0800239 if (nla_put_u8(skb, IFLA_BOND_USE_CARRIER, bond->params.use_carrier))
240 goto nla_put_failure;
241
sfeldma@cumulusnetworks.com06151db2013-12-12 14:10:24 -0800242 if (nla_put_u32(skb, IFLA_BOND_ARP_INTERVAL, bond->params.arp_interval))
243 goto nla_put_failure;
244
sfeldma@cumulusnetworks.com7f28fa12013-12-12 14:10:31 -0800245 targets = nla_nest_start(skb, IFLA_BOND_ARP_IP_TARGET);
246 if (!targets)
247 goto nla_put_failure;
248
249 targets_added = 0;
250 for (i = 0; i < BOND_MAX_ARP_TARGETS; i++) {
251 if (bond->params.arp_targets[i]) {
Jiri Pirkoe7ef9412013-12-14 12:32:10 +0100252 nla_put_be32(skb, i, bond->params.arp_targets[i]);
sfeldma@cumulusnetworks.com7f28fa12013-12-12 14:10:31 -0800253 targets_added = 1;
254 }
255 }
256
257 if (targets_added)
258 nla_nest_end(skb, targets);
259 else
260 nla_nest_cancel(skb, targets);
261
sfeldma@cumulusnetworks.com29c49482013-12-12 14:10:38 -0800262 if (nla_put_u32(skb, IFLA_BOND_ARP_VALIDATE, bond->params.arp_validate))
263 goto nla_put_failure;
264
sfeldma@cumulusnetworks.comd5c84252013-12-12 14:10:45 -0800265 if (nla_put_u32(skb, IFLA_BOND_ARP_ALL_TARGETS,
266 bond->params.arp_all_targets))
267 goto nla_put_failure;
268
sfeldma@cumulusnetworks.com0a98a0d2013-12-15 16:41:51 -0800269 if (bond->primary_slave &&
270 nla_put_u32(skb, IFLA_BOND_PRIMARY,
271 bond->primary_slave->dev->ifindex))
272 goto nla_put_failure;
273
sfeldma@cumulusnetworks.com8a41ae42013-12-15 16:41:58 -0800274 if (nla_put_u8(skb, IFLA_BOND_PRIMARY_RESELECT,
275 bond->params.primary_reselect))
276 goto nla_put_failure;
277
Jiri Pirko90af2312013-10-18 17:43:38 +0200278 return 0;
279
280nla_put_failure:
281 return -EMSGSIZE;
282}
283
Jiri Pirko0a2a78c2013-10-18 17:43:33 +0200284struct rtnl_link_ops bond_link_ops __read_mostly = {
285 .kind = "bond",
286 .priv_size = sizeof(struct bonding),
287 .setup = bond_setup,
Jiri Pirko90af2312013-10-18 17:43:38 +0200288 .maxtype = IFLA_BOND_MAX,
289 .policy = bond_policy,
Jiri Pirko0a2a78c2013-10-18 17:43:33 +0200290 .validate = bond_validate,
Jiri Pirko90af2312013-10-18 17:43:38 +0200291 .newlink = bond_newlink,
292 .changelink = bond_changelink,
293 .get_size = bond_get_size,
294 .fill_info = bond_fill_info,
Jiri Pirko0a2a78c2013-10-18 17:43:33 +0200295 .get_num_tx_queues = bond_get_num_tx_queues,
296 .get_num_rx_queues = bond_get_num_tx_queues, /* Use the same number
297 as for TX queues */
298};
299
300int __init bond_netlink_init(void)
301{
302 return rtnl_link_register(&bond_link_ops);
303}
304
David S. Millera729e832013-10-19 19:09:18 -0400305void bond_netlink_fini(void)
Jiri Pirko0a2a78c2013-10-18 17:43:33 +0200306{
307 rtnl_link_unregister(&bond_link_ops);
308}
309
310MODULE_ALIAS_RTNL_LINK("bond");