blob: 8a71c60fa35768a6ff833475c107d85895e7b778 [file] [log] [blame]
Thomas Gleixner2874c5f2019-05-27 08:55:01 +02001// SPDX-License-Identifier: GPL-2.0-or-later
Stephen Hemminger11dc1f32006-05-25 16:00:12 -07002/*
3 * Bridge netlink control interface
4 *
5 * Authors:
6 * Stephen Hemminger <shemminger@osdl.org>
Stephen Hemminger11dc1f32006-05-25 16:00:12 -07007 */
8
9#include <linux/kernel.h>
Tejun Heo5a0e3ad2010-03-24 17:04:11 +090010#include <linux/slab.h>
stephen hemmingerbb900b22011-04-04 14:03:32 +000011#include <linux/etherdevice.h>
Thomas Graf32fe21c2007-03-22 11:59:03 -070012#include <net/rtnetlink.h>
Eric W. Biederman881d9662007-09-17 11:56:21 -070013#include <net/net_namespace.h>
Denis V. Lunevb8542722007-12-01 00:21:31 +110014#include <net/sock.h>
Vlad Yasevich407af322013-02-13 12:00:12 +000015#include <uapi/linux/if_bridge.h>
stephen hemmingerbb900b22011-04-04 14:03:32 +000016
Stephen Hemminger11dc1f32006-05-25 16:00:12 -070017#include "br_private.h"
Vitalii Demianetsb03b6dd2011-11-25 00:16:37 +000018#include "br_private_stp.h"
Roopa Prabhuefa53562017-01-31 22:59:54 -080019#include "br_private_tunnel.h"
Stephen Hemminger11dc1f32006-05-25 16:00:12 -070020
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020021static int __get_num_vlan_infos(struct net_bridge_vlan_group *vg,
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +020022 u32 filter_mask)
Roopa Prabhufed0a152015-02-25 23:55:40 -080023{
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020024 struct net_bridge_vlan *v;
25 u16 vid_range_start = 0, vid_range_end = 0, vid_range_flags = 0;
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +020026 u16 flags, pvid;
Roopa Prabhufed0a152015-02-25 23:55:40 -080027 int num_vlans = 0;
28
Roopa Prabhufed0a152015-02-25 23:55:40 -080029 if (!(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED))
30 return 0;
31
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +020032 pvid = br_get_pvid(vg);
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020033 /* Count number of vlan infos */
Nikolay Aleksandrov586c2b52015-10-02 15:05:10 +020034 list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
Roopa Prabhufed0a152015-02-25 23:55:40 -080035 flags = 0;
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020036 /* only a context, bridge vlan not activated */
37 if (!br_vlan_should_use(v))
38 continue;
39 if (v->vid == pvid)
Roopa Prabhufed0a152015-02-25 23:55:40 -080040 flags |= BRIDGE_VLAN_INFO_PVID;
41
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020042 if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
Roopa Prabhufed0a152015-02-25 23:55:40 -080043 flags |= BRIDGE_VLAN_INFO_UNTAGGED;
44
45 if (vid_range_start == 0) {
46 goto initvars;
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020047 } else if ((v->vid - vid_range_end) == 1 &&
Roopa Prabhufed0a152015-02-25 23:55:40 -080048 flags == vid_range_flags) {
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020049 vid_range_end = v->vid;
Roopa Prabhufed0a152015-02-25 23:55:40 -080050 continue;
51 } else {
52 if ((vid_range_end - vid_range_start) > 0)
53 num_vlans += 2;
54 else
55 num_vlans += 1;
56 }
57initvars:
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020058 vid_range_start = v->vid;
59 vid_range_end = v->vid;
Roopa Prabhufed0a152015-02-25 23:55:40 -080060 vid_range_flags = flags;
61 }
62
63 if (vid_range_start != 0) {
64 if ((vid_range_end - vid_range_start) > 0)
65 num_vlans += 2;
66 else
67 num_vlans += 1;
68 }
69
70 return num_vlans;
71}
72
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020073static int br_get_num_vlan_infos(struct net_bridge_vlan_group *vg,
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +020074 u32 filter_mask)
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020075{
Nikolay Aleksandrov586c2b52015-10-02 15:05:10 +020076 int num_vlans;
77
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020078 if (!vg)
79 return 0;
80
81 if (filter_mask & RTEXT_FILTER_BRVLAN)
82 return vg->num_vlans;
83
Nikolay Aleksandrov586c2b52015-10-02 15:05:10 +020084 rcu_read_lock();
85 num_vlans = __get_num_vlan_infos(vg, filter_mask);
86 rcu_read_unlock();
87
88 return num_vlans;
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020089}
90
Roopa Prabhufed0a152015-02-25 23:55:40 -080091static size_t br_get_link_af_size_filtered(const struct net_device *dev,
92 u32 filter_mask)
Roopa Prabhub7853d72015-02-21 20:21:51 -080093{
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020094 struct net_bridge_vlan_group *vg = NULL;
Roopa Prabhuefa53562017-01-31 22:59:54 -080095 struct net_bridge_port *p = NULL;
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +020096 struct net_bridge *br;
Roopa Prabhufed0a152015-02-25 23:55:40 -080097 int num_vlan_infos;
Roopa Prabhuefa53562017-01-31 22:59:54 -080098 size_t vinfo_sz = 0;
Roopa Prabhub7853d72015-02-21 20:21:51 -080099
Johannes Berg2f56f6b2015-03-03 16:02:16 +0100100 rcu_read_lock();
Julian Wiedmann35f861e2019-03-29 14:38:19 +0100101 if (netif_is_bridge_port(dev)) {
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200102 p = br_port_get_rcu(dev);
Nikolay Aleksandrov907b1e62015-10-12 21:47:02 +0200103 vg = nbp_vlan_group_rcu(p);
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200104 } else if (dev->priv_flags & IFF_EBRIDGE) {
105 br = netdev_priv(dev);
Nikolay Aleksandrov907b1e62015-10-12 21:47:02 +0200106 vg = br_vlan_group_rcu(br);
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200107 }
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200108 num_vlan_infos = br_get_num_vlan_infos(vg, filter_mask);
Johannes Berg2f56f6b2015-03-03 16:02:16 +0100109 rcu_read_unlock();
Roopa Prabhub7853d72015-02-21 20:21:51 -0800110
Roopa Prabhuefa53562017-01-31 22:59:54 -0800111 if (p && (p->flags & BR_VLAN_TUNNEL))
112 vinfo_sz += br_get_vlan_tunnel_info_size(vg);
113
Roopa Prabhub7853d72015-02-21 20:21:51 -0800114 /* Each VLAN is returned in bridge_vlan_info along with flags */
Roopa Prabhuefa53562017-01-31 22:59:54 -0800115 vinfo_sz += num_vlan_infos * nla_total_size(sizeof(struct bridge_vlan_info));
116
117 return vinfo_sz;
Roopa Prabhub7853d72015-02-21 20:21:51 -0800118}
119
stephen hemminger25c71c72012-11-13 07:53:05 +0000120static inline size_t br_port_info_size(void)
121{
122 return nla_total_size(1) /* IFLA_BRPORT_STATE */
123 + nla_total_size(2) /* IFLA_BRPORT_PRIORITY */
124 + nla_total_size(4) /* IFLA_BRPORT_COST */
125 + nla_total_size(1) /* IFLA_BRPORT_MODE */
stephen hemmingera2e01a62012-11-13 07:53:07 +0000126 + nla_total_size(1) /* IFLA_BRPORT_GUARD */
stephen hemminger1007dd12012-11-13 07:53:08 +0000127 + nla_total_size(1) /* IFLA_BRPORT_PROTECT */
stephen hemminger3da889b2013-03-11 13:52:17 +0000128 + nla_total_size(1) /* IFLA_BRPORT_FAST_LEAVE */
Felix Fietkau6db6f0e2017-01-21 21:01:32 +0100129 + nla_total_size(1) /* IFLA_BRPORT_MCAST_TO_UCAST */
Vlad Yasevich9ba18892013-06-05 10:08:00 -0400130 + nla_total_size(1) /* IFLA_BRPORT_LEARNING */
Vlad Yasevich867a5942013-06-05 10:08:01 -0400131 + nla_total_size(1) /* IFLA_BRPORT_UNICAST_FLOOD */
Tobias Klauser90512472017-05-05 16:36:53 +0200132 + nla_total_size(1) /* IFLA_BRPORT_MCAST_FLOOD */
133 + nla_total_size(1) /* IFLA_BRPORT_BCAST_FLOOD */
Nikolay Aleksandrov355b9f92015-08-04 19:06:32 +0200134 + nla_total_size(1) /* IFLA_BRPORT_PROXYARP */
Nikolay Aleksandrov786c2072015-08-04 19:06:33 +0200135 + nla_total_size(1) /* IFLA_BRPORT_PROXYARP_WIFI */
Roopa Prabhuefa53562017-01-31 22:59:54 -0800136 + nla_total_size(1) /* IFLA_BRPORT_VLAN_TUNNEL */
Roopa Prabhu821f1b22017-10-06 22:12:37 -0700137 + nla_total_size(1) /* IFLA_BRPORT_NEIGH_SUPPRESS */
Nikolay Aleksandrov7d850ab2018-05-24 11:56:48 +0300138 + nla_total_size(1) /* IFLA_BRPORT_ISOLATED */
Nikolay Aleksandrov4ebc7662015-10-06 14:11:55 +0200139 + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_ROOT_ID */
Nikolay Aleksandrov80df9a22015-10-06 14:11:56 +0200140 + nla_total_size(sizeof(struct ifla_bridge_id)) /* IFLA_BRPORT_BRIDGE_ID */
Nikolay Aleksandrov96f94e72015-10-06 14:11:57 +0200141 + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_PORT */
142 + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_DESIGNATED_COST */
Nikolay Aleksandrov42d452c2015-10-06 14:11:58 +0200143 + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_ID */
144 + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_NO */
Nikolay Aleksandrove08e8382015-10-06 14:11:59 +0200145 + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_TOPOLOGY_CHANGE_ACK */
146 + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_CONFIG_PENDING */
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +0200147 + nla_total_size_64bit(sizeof(u64)) /* IFLA_BRPORT_MESSAGE_AGE_TIMER */
148 + nla_total_size_64bit(sizeof(u64)) /* IFLA_BRPORT_FORWARD_DELAY_TIMER */
149 + nla_total_size_64bit(sizeof(u64)) /* IFLA_BRPORT_HOLD_TIMER */
Nikolay Aleksandrov5d6ae472015-10-06 14:12:02 +0200150#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
151 + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MULTICAST_ROUTER */
152#endif
Nikolay Aleksandrov5af48b52017-09-27 16:12:44 +0300153 + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK */
Horatiu Vultur3e544422020-04-26 15:22:01 +0200154 + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MRP_RING_OPEN */
Horatiu Vulturffb3adb2020-07-14 09:34:58 +0200155 + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MRP_IN_OPEN */
stephen hemminger25c71c72012-11-13 07:53:05 +0000156 + 0;
157}
158
Roopa Prabhufed0a152015-02-25 23:55:40 -0800159static inline size_t br_nlmsg_size(struct net_device *dev, u32 filter_mask)
Thomas Graf339bf982006-11-10 14:10:15 -0800160{
161 return NLMSG_ALIGN(sizeof(struct ifinfomsg))
stephen hemminger25c71c72012-11-13 07:53:05 +0000162 + nla_total_size(IFNAMSIZ) /* IFLA_IFNAME */
163 + nla_total_size(MAX_ADDR_LEN) /* IFLA_ADDRESS */
164 + nla_total_size(4) /* IFLA_MASTER */
165 + nla_total_size(4) /* IFLA_MTU */
166 + nla_total_size(4) /* IFLA_LINK */
167 + nla_total_size(1) /* IFLA_OPERSTATE */
Roopa Prabhub7853d72015-02-21 20:21:51 -0800168 + nla_total_size(br_port_info_size()) /* IFLA_PROTINFO */
Roopa Prabhufed0a152015-02-25 23:55:40 -0800169 + nla_total_size(br_get_link_af_size_filtered(dev,
Nikolay Aleksandrov2756f682018-07-23 11:16:59 +0300170 filter_mask)) /* IFLA_AF_SPEC */
171 + nla_total_size(4); /* IFLA_BRPORT_BACKUP_PORT */
stephen hemminger25c71c72012-11-13 07:53:05 +0000172}
173
174static int br_port_fill_attrs(struct sk_buff *skb,
175 const struct net_bridge_port *p)
176{
177 u8 mode = !!(p->flags & BR_HAIRPIN_MODE);
Nikolay Aleksandrov2756f682018-07-23 11:16:59 +0300178 struct net_bridge_port *backup_p;
Nikolay Aleksandrov61c0a9a2015-10-06 14:12:00 +0200179 u64 timerval;
stephen hemminger25c71c72012-11-13 07:53:05 +0000180
181 if (nla_put_u8(skb, IFLA_BRPORT_STATE, p->state) ||
182 nla_put_u16(skb, IFLA_BRPORT_PRIORITY, p->priority) ||
183 nla_put_u32(skb, IFLA_BRPORT_COST, p->path_cost) ||
stephen hemmingera2e01a62012-11-13 07:53:07 +0000184 nla_put_u8(skb, IFLA_BRPORT_MODE, mode) ||
stephen hemminger1007dd12012-11-13 07:53:08 +0000185 nla_put_u8(skb, IFLA_BRPORT_GUARD, !!(p->flags & BR_BPDU_GUARD)) ||
Nikolay Aleksandrovb6cb5ac2016-08-31 15:36:52 +0200186 nla_put_u8(skb, IFLA_BRPORT_PROTECT,
187 !!(p->flags & BR_ROOT_BLOCK)) ||
188 nla_put_u8(skb, IFLA_BRPORT_FAST_LEAVE,
189 !!(p->flags & BR_MULTICAST_FAST_LEAVE)) ||
Felix Fietkau6db6f0e2017-01-21 21:01:32 +0100190 nla_put_u8(skb, IFLA_BRPORT_MCAST_TO_UCAST,
191 !!(p->flags & BR_MULTICAST_TO_UNICAST)) ||
Vlad Yasevich867a5942013-06-05 10:08:01 -0400192 nla_put_u8(skb, IFLA_BRPORT_LEARNING, !!(p->flags & BR_LEARNING)) ||
Nikolay Aleksandrovb6cb5ac2016-08-31 15:36:52 +0200193 nla_put_u8(skb, IFLA_BRPORT_UNICAST_FLOOD,
194 !!(p->flags & BR_FLOOD)) ||
195 nla_put_u8(skb, IFLA_BRPORT_MCAST_FLOOD,
196 !!(p->flags & BR_MCAST_FLOOD)) ||
Mike Manning99f906e2017-04-26 14:48:09 +0100197 nla_put_u8(skb, IFLA_BRPORT_BCAST_FLOOD,
198 !!(p->flags & BR_BCAST_FLOOD)) ||
Jouni Malinen842a9ae2015-03-04 12:54:21 +0200199 nla_put_u8(skb, IFLA_BRPORT_PROXYARP, !!(p->flags & BR_PROXYARP)) ||
200 nla_put_u8(skb, IFLA_BRPORT_PROXYARP_WIFI,
Nikolay Aleksandrov4ebc7662015-10-06 14:11:55 +0200201 !!(p->flags & BR_PROXYARP_WIFI)) ||
202 nla_put(skb, IFLA_BRPORT_ROOT_ID, sizeof(struct ifla_bridge_id),
Nikolay Aleksandrov80df9a22015-10-06 14:11:56 +0200203 &p->designated_root) ||
204 nla_put(skb, IFLA_BRPORT_BRIDGE_ID, sizeof(struct ifla_bridge_id),
Nikolay Aleksandrov96f94e72015-10-06 14:11:57 +0200205 &p->designated_bridge) ||
206 nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_PORT, p->designated_port) ||
Nikolay Aleksandrov42d452c2015-10-06 14:11:58 +0200207 nla_put_u16(skb, IFLA_BRPORT_DESIGNATED_COST, p->designated_cost) ||
208 nla_put_u16(skb, IFLA_BRPORT_ID, p->port_id) ||
Nikolay Aleksandrove08e8382015-10-06 14:11:59 +0200209 nla_put_u16(skb, IFLA_BRPORT_NO, p->port_no) ||
210 nla_put_u8(skb, IFLA_BRPORT_TOPOLOGY_CHANGE_ACK,
211 p->topology_change_ack) ||
Roopa Prabhuefa53562017-01-31 22:59:54 -0800212 nla_put_u8(skb, IFLA_BRPORT_CONFIG_PENDING, p->config_pending) ||
213 nla_put_u8(skb, IFLA_BRPORT_VLAN_TUNNEL, !!(p->flags &
Nikolay Aleksandrov5af48b52017-09-27 16:12:44 +0300214 BR_VLAN_TUNNEL)) ||
Roopa Prabhu821f1b22017-10-06 22:12:37 -0700215 nla_put_u16(skb, IFLA_BRPORT_GROUP_FWD_MASK, p->group_fwd_mask) ||
216 nla_put_u8(skb, IFLA_BRPORT_NEIGH_SUPPRESS,
Nikolay Aleksandrov7d850ab2018-05-24 11:56:48 +0300217 !!(p->flags & BR_NEIGH_SUPPRESS)) ||
Horatiu Vultur3e544422020-04-26 15:22:01 +0200218 nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(p->flags &
219 BR_MRP_LOST_CONT)) ||
Horatiu Vulturffb3adb2020-07-14 09:34:58 +0200220 nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN,
221 !!(p->flags & BR_MRP_LOST_IN_CONT)) ||
Nikolay Aleksandrov7d850ab2018-05-24 11:56:48 +0300222 nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED)))
stephen hemminger25c71c72012-11-13 07:53:05 +0000223 return -EMSGSIZE;
224
Nikolay Aleksandrov61c0a9a2015-10-06 14:12:00 +0200225 timerval = br_timer_value(&p->message_age_timer);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +0200226 if (nla_put_u64_64bit(skb, IFLA_BRPORT_MESSAGE_AGE_TIMER, timerval,
227 IFLA_BRPORT_PAD))
Nikolay Aleksandrov61c0a9a2015-10-06 14:12:00 +0200228 return -EMSGSIZE;
229 timerval = br_timer_value(&p->forward_delay_timer);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +0200230 if (nla_put_u64_64bit(skb, IFLA_BRPORT_FORWARD_DELAY_TIMER, timerval,
231 IFLA_BRPORT_PAD))
Nikolay Aleksandrov61c0a9a2015-10-06 14:12:00 +0200232 return -EMSGSIZE;
233 timerval = br_timer_value(&p->hold_timer);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +0200234 if (nla_put_u64_64bit(skb, IFLA_BRPORT_HOLD_TIMER, timerval,
235 IFLA_BRPORT_PAD))
Nikolay Aleksandrov61c0a9a2015-10-06 14:12:00 +0200236 return -EMSGSIZE;
237
Nikolay Aleksandrov5d6ae472015-10-06 14:12:02 +0200238#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
239 if (nla_put_u8(skb, IFLA_BRPORT_MULTICAST_ROUTER,
240 p->multicast_router))
241 return -EMSGSIZE;
242#endif
243
Nikolay Aleksandrov2756f682018-07-23 11:16:59 +0300244 /* we might be called only with br->lock */
245 rcu_read_lock();
246 backup_p = rcu_dereference(p->backup_port);
247 if (backup_p)
248 nla_put_u32(skb, IFLA_BRPORT_BACKUP_PORT,
249 backup_p->dev->ifindex);
250 rcu_read_unlock();
251
stephen hemminger25c71c72012-11-13 07:53:05 +0000252 return 0;
Thomas Graf339bf982006-11-10 14:10:15 -0800253}
254
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800255static int br_fill_ifvlaninfo_range(struct sk_buff *skb, u16 vid_start,
256 u16 vid_end, u16 flags)
257{
258 struct bridge_vlan_info vinfo;
259
260 if ((vid_end - vid_start) > 0) {
261 /* add range to skb */
262 vinfo.vid = vid_start;
263 vinfo.flags = flags | BRIDGE_VLAN_INFO_RANGE_BEGIN;
264 if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
265 sizeof(vinfo), &vinfo))
266 goto nla_put_failure;
267
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800268 vinfo.vid = vid_end;
269 vinfo.flags = flags | BRIDGE_VLAN_INFO_RANGE_END;
270 if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
271 sizeof(vinfo), &vinfo))
272 goto nla_put_failure;
273 } else {
274 vinfo.vid = vid_start;
275 vinfo.flags = flags;
276 if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
277 sizeof(vinfo), &vinfo))
278 goto nla_put_failure;
279 }
280
281 return 0;
282
283nla_put_failure:
284 return -EMSGSIZE;
285}
286
287static int br_fill_ifvlaninfo_compressed(struct sk_buff *skb,
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200288 struct net_bridge_vlan_group *vg)
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800289{
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200290 struct net_bridge_vlan *v;
291 u16 vid_range_start = 0, vid_range_end = 0, vid_range_flags = 0;
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200292 u16 flags, pvid;
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800293 int err = 0;
294
295 /* Pack IFLA_BRIDGE_VLAN_INFO's for every vlan
296 * and mark vlan info with begin and end flags
297 * if vlaninfo represents a range
298 */
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200299 pvid = br_get_pvid(vg);
Nikolay Aleksandrove9c953e2015-10-12 21:47:03 +0200300 list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800301 flags = 0;
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200302 if (!br_vlan_should_use(v))
303 continue;
304 if (v->vid == pvid)
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800305 flags |= BRIDGE_VLAN_INFO_PVID;
306
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200307 if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800308 flags |= BRIDGE_VLAN_INFO_UNTAGGED;
309
310 if (vid_range_start == 0) {
311 goto initvars;
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200312 } else if ((v->vid - vid_range_end) == 1 &&
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800313 flags == vid_range_flags) {
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200314 vid_range_end = v->vid;
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800315 continue;
316 } else {
317 err = br_fill_ifvlaninfo_range(skb, vid_range_start,
318 vid_range_end,
319 vid_range_flags);
320 if (err)
321 return err;
322 }
323
324initvars:
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200325 vid_range_start = v->vid;
326 vid_range_end = v->vid;
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800327 vid_range_flags = flags;
328 }
329
Roopa Prabhu0fe6de42015-01-12 16:25:28 -0800330 if (vid_range_start != 0) {
331 /* Call it once more to send any left over vlans */
332 err = br_fill_ifvlaninfo_range(skb, vid_range_start,
333 vid_range_end,
334 vid_range_flags);
335 if (err)
336 return err;
337 }
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800338
339 return 0;
340}
341
342static int br_fill_ifvlaninfo(struct sk_buff *skb,
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200343 struct net_bridge_vlan_group *vg)
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800344{
345 struct bridge_vlan_info vinfo;
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200346 struct net_bridge_vlan *v;
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200347 u16 pvid;
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800348
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200349 pvid = br_get_pvid(vg);
Nikolay Aleksandrove9c953e2015-10-12 21:47:03 +0200350 list_for_each_entry_rcu(v, &vg->vlan_list, vlist) {
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200351 if (!br_vlan_should_use(v))
352 continue;
353
354 vinfo.vid = v->vid;
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800355 vinfo.flags = 0;
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200356 if (v->vid == pvid)
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800357 vinfo.flags |= BRIDGE_VLAN_INFO_PVID;
358
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200359 if (v->flags & BRIDGE_VLAN_INFO_UNTAGGED)
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800360 vinfo.flags |= BRIDGE_VLAN_INFO_UNTAGGED;
361
362 if (nla_put(skb, IFLA_BRIDGE_VLAN_INFO,
363 sizeof(vinfo), &vinfo))
364 goto nla_put_failure;
365 }
366
367 return 0;
368
369nla_put_failure:
370 return -EMSGSIZE;
371}
372
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700373/*
374 * Create one netlink message for one interface
375 * Contains port and master info as well as carrier and bridge state.
376 */
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +0000377static int br_fill_ifinfo(struct sk_buff *skb,
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200378 const struct net_bridge_port *port,
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +0000379 u32 pid, u32 seq, int event, unsigned int flags,
380 u32 filter_mask, const struct net_device *dev)
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700381{
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200382 u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN;
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200383 struct net_bridge *br;
Thomas Graf74685962006-11-20 16:20:22 -0800384 struct ifinfomsg *hdr;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700385 struct nlmsghdr *nlh;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700386
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +0000387 if (port)
388 br = port->br;
389 else
390 br = netdev_priv(dev);
391
stephen hemminger28a16c92010-05-10 09:31:09 +0000392 br_debug(br, "br_fill_info event %d port %s master %s\n",
393 event, dev->name, br->dev->name);
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700394
Thomas Graf74685962006-11-20 16:20:22 -0800395 nlh = nlmsg_put(skb, pid, seq, event, sizeof(*hdr), flags);
396 if (nlh == NULL)
Patrick McHardy26932562007-01-31 23:16:40 -0800397 return -EMSGSIZE;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700398
Thomas Graf74685962006-11-20 16:20:22 -0800399 hdr = nlmsg_data(nlh);
400 hdr->ifi_family = AF_BRIDGE;
401 hdr->__ifi_pad = 0;
402 hdr->ifi_type = dev->type;
403 hdr->ifi_index = dev->ifindex;
404 hdr->ifi_flags = dev_get_flags(dev);
405 hdr->ifi_change = 0;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700406
David S. Miller2eb812e2012-04-01 20:49:54 -0400407 if (nla_put_string(skb, IFLA_IFNAME, dev->name) ||
408 nla_put_u32(skb, IFLA_MASTER, br->dev->ifindex) ||
409 nla_put_u32(skb, IFLA_MTU, dev->mtu) ||
410 nla_put_u8(skb, IFLA_OPERSTATE, operstate) ||
411 (dev->addr_len &&
412 nla_put(skb, IFLA_ADDRESS, dev->addr_len, dev->dev_addr)) ||
Nicolas Dichtela54acb32015-04-02 17:07:00 +0200413 (dev->ifindex != dev_get_iflink(dev) &&
414 nla_put_u32(skb, IFLA_LINK, dev_get_iflink(dev))))
David S. Miller2eb812e2012-04-01 20:49:54 -0400415 goto nla_put_failure;
stephen hemminger25c71c72012-11-13 07:53:05 +0000416
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +0000417 if (event == RTM_NEWLINK && port) {
Michal Kubecekf78c6032019-04-26 11:13:12 +0200418 struct nlattr *nest;
stephen hemminger25c71c72012-11-13 07:53:05 +0000419
Michal Kubecekf78c6032019-04-26 11:13:12 +0200420 nest = nla_nest_start(skb, IFLA_PROTINFO);
stephen hemminger25c71c72012-11-13 07:53:05 +0000421 if (nest == NULL || br_port_fill_attrs(skb, port) < 0)
422 goto nla_put_failure;
423 nla_nest_end(skb, nest);
424 }
425
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +0000426 /* Check if the VID information is requested */
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800427 if ((filter_mask & RTEXT_FILTER_BRVLAN) ||
428 (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) {
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200429 struct net_bridge_vlan_group *vg;
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800430 struct nlattr *af;
431 int err;
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +0000432
Nikolay Aleksandrove9c953e2015-10-12 21:47:03 +0200433 /* RCU needed because of the VLAN locking rules (rcu || rtnl) */
434 rcu_read_lock();
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200435 if (port)
Nikolay Aleksandrove9c953e2015-10-12 21:47:03 +0200436 vg = nbp_vlan_group_rcu(port);
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200437 else
Nikolay Aleksandrove9c953e2015-10-12 21:47:03 +0200438 vg = br_vlan_group_rcu(br);
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +0000439
Nikolay Aleksandrove9c953e2015-10-12 21:47:03 +0200440 if (!vg || !vg->num_vlans) {
441 rcu_read_unlock();
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +0000442 goto done;
Nikolay Aleksandrove9c953e2015-10-12 21:47:03 +0200443 }
Michal Kubecekae0be8d2019-04-26 11:13:06 +0200444 af = nla_nest_start_noflag(skb, IFLA_AF_SPEC);
Nikolay Aleksandrove9c953e2015-10-12 21:47:03 +0200445 if (!af) {
446 rcu_read_unlock();
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +0000447 goto nla_put_failure;
Nikolay Aleksandrove9c953e2015-10-12 21:47:03 +0200448 }
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800449 if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200450 err = br_fill_ifvlaninfo_compressed(skb, vg);
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800451 else
Nikolay Aleksandrov77751ee2015-09-30 20:16:53 +0200452 err = br_fill_ifvlaninfo(skb, vg);
Roopa Prabhuefa53562017-01-31 22:59:54 -0800453
454 if (port && (port->flags & BR_VLAN_TUNNEL))
455 err = br_fill_vlan_tunnel_info(skb, vg);
Nikolay Aleksandrove9c953e2015-10-12 21:47:03 +0200456 rcu_read_unlock();
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800457 if (err)
458 goto nla_put_failure;
Horatiu Vultur36a8e8e2020-07-02 10:13:07 +0200459
460 nla_nest_end(skb, af);
461 }
462
463 if (filter_mask & RTEXT_FILTER_MRP) {
464 struct nlattr *af;
465 int err;
466
467 if (!br_mrp_enabled(br) || port)
468 goto done;
469
470 af = nla_nest_start_noflag(skb, IFLA_AF_SPEC);
471 if (!af)
472 goto nla_put_failure;
473
474 rcu_read_lock();
475 err = br_mrp_fill_info(skb, br);
476 rcu_read_unlock();
477
478 if (err)
479 goto nla_put_failure;
480
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +0000481 nla_nest_end(skb, af);
482 }
483
484done:
Johannes Berg053c0952015-01-16 22:09:00 +0100485 nlmsg_end(skb, nlh);
486 return 0;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700487
Thomas Graf74685962006-11-20 16:20:22 -0800488nla_put_failure:
Patrick McHardy26932562007-01-31 23:16:40 -0800489 nlmsg_cancel(skb, nlh);
490 return -EMSGSIZE;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700491}
492
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200493/* Notify listeners of a change in bridge or port information */
494void br_ifinfo_notify(int event, const struct net_bridge *br,
495 const struct net_bridge_port *port)
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700496{
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200497 u32 filter = RTEXT_FILTER_BRVLAN_COMPRESSED;
498 struct net_device *dev;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700499 struct sk_buff *skb;
Thomas Graf280a3062006-08-15 00:36:28 -0700500 int err = -ENOBUFS;
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200501 struct net *net;
502 u16 port_no = 0;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700503
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200504 if (WARN_ON(!port && !br))
Vlad Yasevich407af322013-02-13 12:00:12 +0000505 return;
506
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200507 if (port) {
508 dev = port->dev;
509 br = port->br;
510 port_no = port->port_no;
511 } else {
512 dev = br->dev;
513 }
stephen hemminger28a16c92010-05-10 09:31:09 +0000514
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200515 net = dev_net(dev);
516 br_debug(br, "port %u(%s) event %d\n", port_no, dev->name, event);
517
518 skb = nlmsg_new(br_nlmsg_size(dev, filter), GFP_ATOMIC);
Thomas Graf280a3062006-08-15 00:36:28 -0700519 if (skb == NULL)
520 goto errout;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700521
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200522 err = br_fill_ifinfo(skb, port, 0, 0, event, 0, filter, dev);
Patrick McHardy26932562007-01-31 23:16:40 -0800523 if (err < 0) {
524 /* -EMSGSIZE implies BUG in br_nlmsg_size() */
525 WARN_ON(err == -EMSGSIZE);
526 kfree_skb(skb);
527 goto errout;
528 }
Pablo Neira Ayuso1ce85fe2009-02-24 23:18:28 -0800529 rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
530 return;
Thomas Graf280a3062006-08-15 00:36:28 -0700531errout:
tanxiaojun87e823b2013-12-19 13:28:10 +0800532 rtnl_set_sk_err(net, RTNLGRP_LINK, err);
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700533}
534
535/*
536 * Dump information about all ports, in response to GETLINK
537 */
John Fastabende5a55a82012-10-24 08:12:57 +0000538int br_getlink(struct sk_buff *skb, u32 pid, u32 seq,
Nicolas Dichtel46c264d2015-04-28 18:33:49 +0200539 struct net_device *dev, u32 filter_mask, int nlflags)
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700540{
Hong Zhiguo1fb17542013-09-14 22:42:27 +0800541 struct net_bridge_port *port = br_port_get_rtnl(dev);
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700542
Roopa Prabhu36cd0ff2015-01-10 07:31:14 -0800543 if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN) &&
Horatiu Vultur36a8e8e2020-07-02 10:13:07 +0200544 !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) &&
545 !(filter_mask & RTEXT_FILTER_MRP))
Dan Carpenter1b846f92015-01-21 12:22:35 +0300546 return 0;
stephen hemmingerb5ed54e2010-11-15 06:38:13 +0000547
Nicolas Dichtel46c264d2015-04-28 18:33:49 +0200548 return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, nlflags,
Dan Carpenter1b846f92015-01-21 12:22:35 +0300549 filter_mask, dev);
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700550}
551
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800552static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p,
Petr Machata169327d2018-12-12 17:02:50 +0000553 int cmd, struct bridge_vlan_info *vinfo, bool *changed,
554 struct netlink_ext_ack *extack)
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800555{
Nikolay Aleksandrovf418af62017-10-27 13:19:37 +0300556 bool curr_change;
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800557 int err = 0;
558
559 switch (cmd) {
560 case RTM_SETLINK:
561 if (p) {
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200562 /* if the MASTER flag is set this will act on the global
563 * per-VLAN entry as well
564 */
Nikolay Aleksandrovf418af62017-10-27 13:19:37 +0300565 err = nbp_vlan_add(p, vinfo->vid, vinfo->flags,
Petr Machata169327d2018-12-12 17:02:50 +0000566 &curr_change, extack);
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800567 } else {
Nikolay Aleksandrov2594e9062015-09-25 19:00:11 +0200568 vinfo->flags |= BRIDGE_VLAN_INFO_BRENTRY;
Nikolay Aleksandrovf418af62017-10-27 13:19:37 +0300569 err = br_vlan_add(br, vinfo->vid, vinfo->flags,
Petr Machata169327d2018-12-12 17:02:50 +0000570 &curr_change, extack);
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800571 }
Nikolay Aleksandrovf418af62017-10-27 13:19:37 +0300572 if (curr_change)
Nikolay Aleksandrove19b42a2017-10-27 13:19:36 +0300573 *changed = true;
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800574 break;
575
576 case RTM_DELLINK:
577 if (p) {
Nikolay Aleksandrove19b42a2017-10-27 13:19:36 +0300578 if (!nbp_vlan_delete(p, vinfo->vid))
579 *changed = true;
580
581 if ((vinfo->flags & BRIDGE_VLAN_INFO_MASTER) &&
582 !br_vlan_delete(p->br, vinfo->vid))
583 *changed = true;
584 } else if (!br_vlan_delete(br, vinfo->vid)) {
585 *changed = true;
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800586 }
587 break;
588 }
589
590 return err;
591}
Vlad Yasevich407af322013-02-13 12:00:12 +0000592
Nikolay Aleksandrovf26b2962020-01-14 19:56:10 +0200593int br_process_vlan_info(struct net_bridge *br,
594 struct net_bridge_port *p, int cmd,
595 struct bridge_vlan_info *vinfo_curr,
596 struct bridge_vlan_info **vinfo_last,
597 bool *changed,
598 struct netlink_ext_ack *extack)
Roopa Prabhuefa53562017-01-31 22:59:54 -0800599{
Nikolay Aleksandrovf5459232020-01-14 19:56:14 +0200600 int err, rtm_cmd;
601
Nikolay Aleksandrov8f4cc942020-01-14 19:56:08 +0200602 if (!br_vlan_valid_id(vinfo_curr->vid, extack))
Roopa Prabhuefa53562017-01-31 22:59:54 -0800603 return -EINVAL;
604
Nikolay Aleksandrovf5459232020-01-14 19:56:14 +0200605 /* needed for vlan-only NEWVLAN/DELVLAN notifications */
606 rtm_cmd = br_afspec_cmd_to_rtm(cmd);
607
Roopa Prabhuefa53562017-01-31 22:59:54 -0800608 if (vinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) {
Nikolay Aleksandrov8f4cc942020-01-14 19:56:08 +0200609 if (!br_vlan_valid_range(vinfo_curr, *vinfo_last, extack))
Roopa Prabhuefa53562017-01-31 22:59:54 -0800610 return -EINVAL;
611 *vinfo_last = vinfo_curr;
Roopa Prabhuefa53562017-01-31 22:59:54 -0800612 return 0;
613 }
614
615 if (*vinfo_last) {
616 struct bridge_vlan_info tmp_vinfo;
Nikolay Aleksandrovf5459232020-01-14 19:56:14 +0200617 int v, v_change_start = 0;
Roopa Prabhuefa53562017-01-31 22:59:54 -0800618
Nikolay Aleksandrov8f4cc942020-01-14 19:56:08 +0200619 if (!br_vlan_valid_range(vinfo_curr, *vinfo_last, extack))
Roopa Prabhuefa53562017-01-31 22:59:54 -0800620 return -EINVAL;
621
622 memcpy(&tmp_vinfo, *vinfo_last,
623 sizeof(struct bridge_vlan_info));
624 for (v = (*vinfo_last)->vid; v <= vinfo_curr->vid; v++) {
Nikolay Aleksandrovf5459232020-01-14 19:56:14 +0200625 bool curr_change = false;
626
Roopa Prabhuefa53562017-01-31 22:59:54 -0800627 tmp_vinfo.vid = v;
Nikolay Aleksandrovf5459232020-01-14 19:56:14 +0200628 err = br_vlan_info(br, p, cmd, &tmp_vinfo, &curr_change,
Petr Machata169327d2018-12-12 17:02:50 +0000629 extack);
Roopa Prabhuefa53562017-01-31 22:59:54 -0800630 if (err)
631 break;
Nikolay Aleksandrovf5459232020-01-14 19:56:14 +0200632 if (curr_change) {
633 *changed = curr_change;
634 if (!v_change_start)
635 v_change_start = v;
636 } else {
637 /* nothing to notify yet */
638 if (!v_change_start)
639 continue;
640 br_vlan_notify(br, p, v_change_start,
641 v - 1, rtm_cmd);
642 v_change_start = 0;
643 }
Ido Schimmel79794572020-04-30 22:38:45 +0300644 cond_resched();
Roopa Prabhuefa53562017-01-31 22:59:54 -0800645 }
Nikolay Aleksandrovf5459232020-01-14 19:56:14 +0200646 /* v_change_start is set only if the last/whole range changed */
647 if (v_change_start)
648 br_vlan_notify(br, p, v_change_start,
649 v - 1, rtm_cmd);
650
Roopa Prabhuefa53562017-01-31 22:59:54 -0800651 *vinfo_last = NULL;
652
Nikolay Aleksandrov66c54512017-10-19 20:17:32 +0300653 return err;
Roopa Prabhuefa53562017-01-31 22:59:54 -0800654 }
655
Nikolay Aleksandrovf5459232020-01-14 19:56:14 +0200656 err = br_vlan_info(br, p, cmd, vinfo_curr, changed, extack);
657 if (*changed)
658 br_vlan_notify(br, p, vinfo_curr->vid, 0, rtm_cmd);
659
660 return err;
Roopa Prabhuefa53562017-01-31 22:59:54 -0800661}
662
Vlad Yasevich407af322013-02-13 12:00:12 +0000663static int br_afspec(struct net_bridge *br,
664 struct net_bridge_port *p,
665 struct nlattr *af_spec,
Petr Machata169327d2018-12-12 17:02:50 +0000666 int cmd, bool *changed,
667 struct netlink_ext_ack *extack)
Vlad Yasevich407af322013-02-13 12:00:12 +0000668{
Roopa Prabhuefa53562017-01-31 22:59:54 -0800669 struct bridge_vlan_info *vinfo_curr = NULL;
670 struct bridge_vlan_info *vinfo_last = NULL;
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800671 struct nlattr *attr;
Roopa Prabhuefa53562017-01-31 22:59:54 -0800672 struct vtunnel_info tinfo_last = {};
673 struct vtunnel_info tinfo_curr = {};
674 int err = 0, rem;
Vlad Yasevich407af322013-02-13 12:00:12 +0000675
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800676 nla_for_each_nested(attr, af_spec, rem) {
Roopa Prabhuefa53562017-01-31 22:59:54 -0800677 err = 0;
678 switch (nla_type(attr)) {
679 case IFLA_BRIDGE_VLAN_TUNNEL_INFO:
Nikolay Aleksandrov1020ce32017-06-06 01:26:24 +0300680 if (!p || !(p->flags & BR_VLAN_TUNNEL))
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800681 return -EINVAL;
Roopa Prabhuefa53562017-01-31 22:59:54 -0800682 err = br_parse_vlan_tunnel_info(attr, &tinfo_curr);
683 if (err)
684 return err;
685 err = br_process_vlan_tunnel_info(br, p, cmd,
686 &tinfo_curr,
Nikolay Aleksandrove19b42a2017-10-27 13:19:36 +0300687 &tinfo_last,
688 changed);
Roopa Prabhuefa53562017-01-31 22:59:54 -0800689 if (err)
690 return err;
Roopa Prabhubdced7e2015-01-10 07:31:12 -0800691 break;
Roopa Prabhuefa53562017-01-31 22:59:54 -0800692 case IFLA_BRIDGE_VLAN_INFO:
693 if (nla_len(attr) != sizeof(struct bridge_vlan_info))
694 return -EINVAL;
695 vinfo_curr = nla_data(attr);
696 err = br_process_vlan_info(br, p, cmd, vinfo_curr,
Petr Machata169327d2018-12-12 17:02:50 +0000697 &vinfo_last, changed,
698 extack);
Roopa Prabhuefa53562017-01-31 22:59:54 -0800699 if (err)
700 return err;
701 break;
Horatiu Vultur65369932020-04-26 15:22:07 +0200702 case IFLA_BRIDGE_MRP:
703 err = br_mrp_parse(br, p, attr, cmd, extack);
704 if (err)
705 return err;
706 break;
Roopa Prabhuefa53562017-01-31 22:59:54 -0800707 }
Vlad Yasevich407af322013-02-13 12:00:12 +0000708 }
709
710 return err;
711}
712
Jiri Pirko3ac636b2014-09-05 15:51:30 +0200713static const struct nla_policy br_port_policy[IFLA_BRPORT_MAX + 1] = {
stephen hemminger25c71c72012-11-13 07:53:05 +0000714 [IFLA_BRPORT_STATE] = { .type = NLA_U8 },
715 [IFLA_BRPORT_COST] = { .type = NLA_U32 },
716 [IFLA_BRPORT_PRIORITY] = { .type = NLA_U16 },
717 [IFLA_BRPORT_MODE] = { .type = NLA_U8 },
stephen hemmingera2e01a62012-11-13 07:53:07 +0000718 [IFLA_BRPORT_GUARD] = { .type = NLA_U8 },
stephen hemminger1007dd12012-11-13 07:53:08 +0000719 [IFLA_BRPORT_PROTECT] = { .type = NLA_U8 },
Thomas Graf6f705d82014-11-26 13:42:19 +0100720 [IFLA_BRPORT_FAST_LEAVE]= { .type = NLA_U8 },
Vlad Yasevich9ba18892013-06-05 10:08:00 -0400721 [IFLA_BRPORT_LEARNING] = { .type = NLA_U8 },
Vlad Yasevich867a5942013-06-05 10:08:01 -0400722 [IFLA_BRPORT_UNICAST_FLOOD] = { .type = NLA_U8 },
Nikolay Aleksandrov355b9f92015-08-04 19:06:32 +0200723 [IFLA_BRPORT_PROXYARP] = { .type = NLA_U8 },
Nikolay Aleksandrov786c2072015-08-04 19:06:33 +0200724 [IFLA_BRPORT_PROXYARP_WIFI] = { .type = NLA_U8 },
Nikolay Aleksandrov5d6ae472015-10-06 14:12:02 +0200725 [IFLA_BRPORT_MULTICAST_ROUTER] = { .type = NLA_U8 },
Felix Fietkau6db6f0e2017-01-21 21:01:32 +0100726 [IFLA_BRPORT_MCAST_TO_UCAST] = { .type = NLA_U8 },
Tobias Klauser90512472017-05-05 16:36:53 +0200727 [IFLA_BRPORT_MCAST_FLOOD] = { .type = NLA_U8 },
728 [IFLA_BRPORT_BCAST_FLOOD] = { .type = NLA_U8 },
Nikolay Aleksandrovfbec4432017-11-13 18:30:55 +0200729 [IFLA_BRPORT_VLAN_TUNNEL] = { .type = NLA_U8 },
Nikolay Aleksandrov5af48b52017-09-27 16:12:44 +0300730 [IFLA_BRPORT_GROUP_FWD_MASK] = { .type = NLA_U16 },
Nikolay Aleksandrov1a3fbd32017-10-30 12:56:33 +0200731 [IFLA_BRPORT_NEIGH_SUPPRESS] = { .type = NLA_U8 },
Nikolay Aleksandrov7d850ab2018-05-24 11:56:48 +0300732 [IFLA_BRPORT_ISOLATED] = { .type = NLA_U8 },
Nikolay Aleksandrov2756f682018-07-23 11:16:59 +0300733 [IFLA_BRPORT_BACKUP_PORT] = { .type = NLA_U32 },
stephen hemminger25c71c72012-11-13 07:53:05 +0000734};
735
736/* Change the state of the port and notify spanning tree */
737static int br_set_port_state(struct net_bridge_port *p, u8 state)
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700738{
stephen hemminger25c71c72012-11-13 07:53:05 +0000739 if (state > BR_STATE_BLOCKING)
stephen hemmingerb5ed54e2010-11-15 06:38:13 +0000740 return -EINVAL;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700741
742 /* if kernel STP is running, don't allow changes */
Stephen Hemminger9cde0702007-03-21 14:22:44 -0700743 if (p->br->stp_enabled == BR_KERNEL_STP)
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700744 return -EBUSY;
745
stephen hemminger576eb622012-12-28 18:15:22 +0000746 /* if device is not up, change is not allowed
747 * if link is not present, only allowable state is disabled
748 */
stephen hemminger25c71c72012-11-13 07:53:05 +0000749 if (!netif_running(p->dev) ||
stephen hemminger576eb622012-12-28 18:15:22 +0000750 (!netif_oper_up(p->dev) && state != BR_STATE_DISABLED))
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700751 return -ENETDOWN;
752
Florian Fainelli775dd692014-09-30 16:13:19 -0700753 br_set_state(p, state);
Vitalii Demianetsb03b6dd2011-11-25 00:16:37 +0000754 br_port_state_selection(p->br);
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700755 return 0;
756}
757
stephen hemminger25c71c72012-11-13 07:53:05 +0000758/* Set/clear or port flags based on attribute */
Arkadi Sharshevsky39222852017-06-08 08:44:11 +0200759static int br_set_port_flag(struct net_bridge_port *p, struct nlattr *tb[],
760 int attrtype, unsigned long mask)
stephen hemminger25c71c72012-11-13 07:53:05 +0000761{
Arkadi Sharshevsky39222852017-06-08 08:44:11 +0200762 unsigned long flags;
763 int err;
764
765 if (!tb[attrtype])
766 return 0;
767
768 if (nla_get_u8(tb[attrtype]))
769 flags = p->flags | mask;
770 else
771 flags = p->flags & ~mask;
772
773 err = br_switchdev_set_port_flag(p, flags, mask);
774 if (err)
775 return err;
776
777 p->flags = flags;
778 return 0;
stephen hemminger25c71c72012-11-13 07:53:05 +0000779}
780
781/* Process bridge protocol info on port */
782static int br_setport(struct net_bridge_port *p, struct nlattr *tb[])
783{
Vlad Yaseviche028e4b2014-05-16 09:59:16 -0400784 unsigned long old_flags = p->flags;
Roopa Prabhuefa53562017-01-31 22:59:54 -0800785 bool br_vlan_tunnel_old = false;
786 int err;
stephen hemminger25c71c72012-11-13 07:53:05 +0000787
Arkadi Sharshevsky39222852017-06-08 08:44:11 +0200788 err = br_set_port_flag(p, tb, IFLA_BRPORT_MODE, BR_HAIRPIN_MODE);
789 if (err)
790 return err;
791
792 err = br_set_port_flag(p, tb, IFLA_BRPORT_GUARD, BR_BPDU_GUARD);
793 if (err)
794 return err;
795
796 err = br_set_port_flag(p, tb, IFLA_BRPORT_FAST_LEAVE, BR_MULTICAST_FAST_LEAVE);
797 if (err)
798 return err;
799
800 err = br_set_port_flag(p, tb, IFLA_BRPORT_PROTECT, BR_ROOT_BLOCK);
801 if (err)
802 return err;
803
804 err = br_set_port_flag(p, tb, IFLA_BRPORT_LEARNING, BR_LEARNING);
805 if (err)
806 return err;
807
808 err = br_set_port_flag(p, tb, IFLA_BRPORT_UNICAST_FLOOD, BR_FLOOD);
809 if (err)
810 return err;
811
812 err = br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_FLOOD, BR_MCAST_FLOOD);
813 if (err)
814 return err;
815
816 err = br_set_port_flag(p, tb, IFLA_BRPORT_MCAST_TO_UCAST, BR_MULTICAST_TO_UNICAST);
817 if (err)
818 return err;
819
820 err = br_set_port_flag(p, tb, IFLA_BRPORT_BCAST_FLOOD, BR_BCAST_FLOOD);
821 if (err)
822 return err;
823
824 err = br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP, BR_PROXYARP);
825 if (err)
826 return err;
827
828 err = br_set_port_flag(p, tb, IFLA_BRPORT_PROXYARP_WIFI, BR_PROXYARP_WIFI);
829 if (err)
830 return err;
stephen hemminger25c71c72012-11-13 07:53:05 +0000831
Roopa Prabhuefa53562017-01-31 22:59:54 -0800832 br_vlan_tunnel_old = (p->flags & BR_VLAN_TUNNEL) ? true : false;
Arkadi Sharshevsky39222852017-06-08 08:44:11 +0200833 err = br_set_port_flag(p, tb, IFLA_BRPORT_VLAN_TUNNEL, BR_VLAN_TUNNEL);
834 if (err)
835 return err;
836
Roopa Prabhuefa53562017-01-31 22:59:54 -0800837 if (br_vlan_tunnel_old && !(p->flags & BR_VLAN_TUNNEL))
838 nbp_vlan_tunnel_info_flush(p);
839
stephen hemminger25c71c72012-11-13 07:53:05 +0000840 if (tb[IFLA_BRPORT_COST]) {
841 err = br_stp_set_path_cost(p, nla_get_u32(tb[IFLA_BRPORT_COST]));
842 if (err)
843 return err;
844 }
845
846 if (tb[IFLA_BRPORT_PRIORITY]) {
847 err = br_stp_set_port_priority(p, nla_get_u16(tb[IFLA_BRPORT_PRIORITY]));
848 if (err)
849 return err;
850 }
851
852 if (tb[IFLA_BRPORT_STATE]) {
853 err = br_set_port_state(p, nla_get_u8(tb[IFLA_BRPORT_STATE]));
854 if (err)
855 return err;
856 }
Vlad Yaseviche028e4b2014-05-16 09:59:16 -0400857
Nikolay Aleksandrov9b0c6e42015-10-06 14:12:01 +0200858 if (tb[IFLA_BRPORT_FLUSH])
859 br_fdb_delete_by_port(p->br, p, 0, 0);
860
Nikolay Aleksandrov5d6ae472015-10-06 14:12:02 +0200861#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
862 if (tb[IFLA_BRPORT_MULTICAST_ROUTER]) {
863 u8 mcast_router = nla_get_u8(tb[IFLA_BRPORT_MULTICAST_ROUTER]);
864
865 err = br_multicast_set_port_router(p, mcast_router);
866 if (err)
867 return err;
868 }
869#endif
Nikolay Aleksandrov5af48b52017-09-27 16:12:44 +0300870
871 if (tb[IFLA_BRPORT_GROUP_FWD_MASK]) {
872 u16 fwd_mask = nla_get_u16(tb[IFLA_BRPORT_GROUP_FWD_MASK]);
873
874 if (fwd_mask & BR_GROUPFWD_MACPAUSE)
875 return -EINVAL;
876 p->group_fwd_mask = fwd_mask;
877 }
878
Roopa Prabhu821f1b22017-10-06 22:12:37 -0700879 err = br_set_port_flag(p, tb, IFLA_BRPORT_NEIGH_SUPPRESS,
880 BR_NEIGH_SUPPRESS);
881 if (err)
882 return err;
883
Nikolay Aleksandrov7d850ab2018-05-24 11:56:48 +0300884 err = br_set_port_flag(p, tb, IFLA_BRPORT_ISOLATED, BR_ISOLATED);
885 if (err)
886 return err;
887
Nikolay Aleksandrov2756f682018-07-23 11:16:59 +0300888 if (tb[IFLA_BRPORT_BACKUP_PORT]) {
889 struct net_device *backup_dev = NULL;
890 u32 backup_ifindex;
891
892 backup_ifindex = nla_get_u32(tb[IFLA_BRPORT_BACKUP_PORT]);
893 if (backup_ifindex) {
894 backup_dev = __dev_get_by_index(dev_net(p->dev),
895 backup_ifindex);
896 if (!backup_dev)
897 return -ENOENT;
898 }
899
900 err = nbp_backup_change(p, backup_dev);
901 if (err)
902 return err;
903 }
904
Vlad Yaseviche028e4b2014-05-16 09:59:16 -0400905 br_port_flags_change(p, old_flags ^ p->flags);
stephen hemminger25c71c72012-11-13 07:53:05 +0000906 return 0;
907}
908
909/* Change state and parameters on port. */
Petr Machata2fd527b2018-12-12 17:02:48 +0000910int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags,
911 struct netlink_ext_ack *extack)
stephen hemminger25c71c72012-11-13 07:53:05 +0000912{
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200913 struct net_bridge *br = (struct net_bridge *)netdev_priv(dev);
914 struct nlattr *tb[IFLA_BRPORT_MAX + 1];
915 struct net_bridge_port *p;
stephen hemminger25c71c72012-11-13 07:53:05 +0000916 struct nlattr *protinfo;
Vlad Yasevich407af322013-02-13 12:00:12 +0000917 struct nlattr *afspec;
Nikolay Aleksandrove19b42a2017-10-27 13:19:36 +0300918 bool changed = false;
Scott Feldman41c498b2015-05-10 09:47:59 -0700919 int err = 0;
stephen hemminger25c71c72012-11-13 07:53:05 +0000920
Hong zhi guoc60ee672013-03-28 06:21:22 +0000921 protinfo = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_PROTINFO);
922 afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
Vlad Yasevich407af322013-02-13 12:00:12 +0000923 if (!protinfo && !afspec)
stephen hemminger25c71c72012-11-13 07:53:05 +0000924 return 0;
925
926 p = br_port_get_rtnl(dev);
Vlad Yasevich407af322013-02-13 12:00:12 +0000927 /* We want to accept dev as bridge itself if the AF_SPEC
stephen hemminger8e3bff92013-12-08 12:15:44 -0800928 * is set to see if someone is setting vlan info on the bridge
Vlad Yasevich407af322013-02-13 12:00:12 +0000929 */
Hong zhi guo7b99a992013-03-24 03:26:47 +0000930 if (!p && !afspec)
stephen hemminger25c71c72012-11-13 07:53:05 +0000931 return -EINVAL;
932
Vlad Yasevich407af322013-02-13 12:00:12 +0000933 if (p && protinfo) {
934 if (protinfo->nla_type & NLA_F_NESTED) {
Johannes Berg8cb08172019-04-26 14:07:28 +0200935 err = nla_parse_nested_deprecated(tb, IFLA_BRPORT_MAX,
936 protinfo,
937 br_port_policy,
938 NULL);
Vlad Yasevich407af322013-02-13 12:00:12 +0000939 if (err)
940 return err;
941
942 spin_lock_bh(&p->br->lock);
943 err = br_setport(p, tb);
944 spin_unlock_bh(&p->br->lock);
945 } else {
stephen hemminger8e3bff92013-12-08 12:15:44 -0800946 /* Binary compatibility with old RSTP */
Vlad Yasevich407af322013-02-13 12:00:12 +0000947 if (nla_len(protinfo) < sizeof(u8))
948 return -EINVAL;
949
950 spin_lock_bh(&p->br->lock);
951 err = br_set_port_state(p, nla_get_u8(protinfo));
952 spin_unlock_bh(&p->br->lock);
953 }
stephen hemminger25c71c72012-11-13 07:53:05 +0000954 if (err)
Vlad Yasevich407af322013-02-13 12:00:12 +0000955 goto out;
Nikolay Aleksandrove19b42a2017-10-27 13:19:36 +0300956 changed = true;
Vlad Yasevich407af322013-02-13 12:00:12 +0000957 }
stephen hemminger25c71c72012-11-13 07:53:05 +0000958
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200959 if (afspec)
Petr Machata169327d2018-12-12 17:02:50 +0000960 err = br_afspec(br, p, afspec, RTM_SETLINK, &changed, extack);
stephen hemminger25c71c72012-11-13 07:53:05 +0000961
Nikolay Aleksandrove19b42a2017-10-27 13:19:36 +0300962 if (changed)
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200963 br_ifinfo_notify(RTM_NEWLINK, br, p);
Vlad Yasevich407af322013-02-13 12:00:12 +0000964out:
stephen hemminger25c71c72012-11-13 07:53:05 +0000965 return err;
966}
967
Vlad Yasevich407af322013-02-13 12:00:12 +0000968/* Delete port information */
Roopa Prabhuadd511b2015-01-29 22:40:12 -0800969int br_dellink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags)
Vlad Yasevich407af322013-02-13 12:00:12 +0000970{
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200971 struct net_bridge *br = (struct net_bridge *)netdev_priv(dev);
Vlad Yasevich407af322013-02-13 12:00:12 +0000972 struct net_bridge_port *p;
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200973 struct nlattr *afspec;
Nikolay Aleksandrove19b42a2017-10-27 13:19:36 +0300974 bool changed = false;
Scott Feldman85080252015-05-10 09:48:03 -0700975 int err = 0;
Vlad Yasevich407af322013-02-13 12:00:12 +0000976
Hong zhi guoc60ee672013-03-28 06:21:22 +0000977 afspec = nlmsg_find_attr(nlh, sizeof(struct ifinfomsg), IFLA_AF_SPEC);
Vlad Yasevich407af322013-02-13 12:00:12 +0000978 if (!afspec)
979 return 0;
980
981 p = br_port_get_rtnl(dev);
982 /* We want to accept dev as bridge itself as well */
983 if (!p && !(dev->priv_flags & IFF_EBRIDGE))
984 return -EINVAL;
985
Petr Machata169327d2018-12-12 17:02:50 +0000986 err = br_afspec(br, p, afspec, RTM_DELLINK, &changed, NULL);
Nikolay Aleksandrove19b42a2017-10-27 13:19:36 +0300987 if (changed)
Roopa Prabhu02dba432015-01-14 20:02:25 -0800988 /* Send RTM_NEWLINK because userspace
989 * expects RTM_NEWLINK for vlan dels
990 */
Nikolay Aleksandrov92899062017-11-01 12:18:13 +0200991 br_ifinfo_notify(RTM_NEWLINK, br, p);
Vlad Yasevich407af322013-02-13 12:00:12 +0000992
993 return err;
994}
Matthias Schiffera8b8a8892017-06-25 23:56:01 +0200995
996static int br_validate(struct nlattr *tb[], struct nlattr *data[],
997 struct netlink_ext_ack *extack)
Stephen Hemminger11dc1f32006-05-25 16:00:12 -0700998{
stephen hemmingerbb900b22011-04-04 14:03:32 +0000999 if (tb[IFLA_ADDRESS]) {
1000 if (nla_len(tb[IFLA_ADDRESS]) != ETH_ALEN)
1001 return -EINVAL;
1002 if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
1003 return -EADDRNOTAVAIL;
1004 }
Thomas Graf32fe21c2007-03-22 11:59:03 -07001005
Toshiaki Makitad2d427b2015-08-27 15:32:26 +09001006 if (!data)
1007 return 0;
1008
1009#ifdef CONFIG_BRIDGE_VLAN_FILTERING
1010 if (data[IFLA_BR_VLAN_PROTOCOL]) {
1011 switch (nla_get_be16(data[IFLA_BR_VLAN_PROTOCOL])) {
1012 case htons(ETH_P_8021Q):
1013 case htons(ETH_P_8021AD):
1014 break;
1015 default:
1016 return -EPROTONOSUPPORT;
1017 }
1018 }
Tobias Jungela2858602017-05-17 09:29:12 +02001019
1020 if (data[IFLA_BR_VLAN_DEFAULT_PVID]) {
1021 __u16 defpvid = nla_get_u16(data[IFLA_BR_VLAN_DEFAULT_PVID]);
1022
1023 if (defpvid >= VLAN_VID_MASK)
1024 return -EINVAL;
1025 }
Toshiaki Makitad2d427b2015-08-27 15:32:26 +09001026#endif
1027
Thomas Graf32fe21c2007-03-22 11:59:03 -07001028 return 0;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -07001029}
1030
Jiri Pirko3ac636b2014-09-05 15:51:30 +02001031static int br_port_slave_changelink(struct net_device *brdev,
1032 struct net_device *dev,
1033 struct nlattr *tb[],
Matthias Schiffer17dd0ec2017-06-25 23:56:02 +02001034 struct nlattr *data[],
1035 struct netlink_ext_ack *extack)
Jiri Pirko3ac636b2014-09-05 15:51:30 +02001036{
Nikolay Aleksandrov963ad942015-07-22 13:03:40 +02001037 struct net_bridge *br = netdev_priv(brdev);
1038 int ret;
1039
Jiri Pirko3ac636b2014-09-05 15:51:30 +02001040 if (!data)
1041 return 0;
Nikolay Aleksandrov963ad942015-07-22 13:03:40 +02001042
1043 spin_lock_bh(&br->lock);
1044 ret = br_setport(br_port_get_rtnl(dev), data);
1045 spin_unlock_bh(&br->lock);
1046
1047 return ret;
Jiri Pirko3ac636b2014-09-05 15:51:30 +02001048}
1049
Jiri Pirkoced82832014-09-05 15:51:29 +02001050static int br_port_fill_slave_info(struct sk_buff *skb,
1051 const struct net_device *brdev,
1052 const struct net_device *dev)
1053{
1054 return br_port_fill_attrs(skb, br_port_get_rtnl(dev));
1055}
1056
1057static size_t br_port_get_slave_size(const struct net_device *brdev,
1058 const struct net_device *dev)
1059{
1060 return br_port_info_size();
1061}
1062
Jiri Pirko13323512014-09-05 15:51:32 +02001063static const struct nla_policy br_policy[IFLA_BR_MAX + 1] = {
1064 [IFLA_BR_FORWARD_DELAY] = { .type = NLA_U32 },
1065 [IFLA_BR_HELLO_TIME] = { .type = NLA_U32 },
1066 [IFLA_BR_MAX_AGE] = { .type = NLA_U32 },
Jörg Thalheimaf615762015-03-18 10:06:58 +01001067 [IFLA_BR_AGEING_TIME] = { .type = NLA_U32 },
1068 [IFLA_BR_STP_STATE] = { .type = NLA_U32 },
1069 [IFLA_BR_PRIORITY] = { .type = NLA_U16 },
Nikolay Aleksandrova7854032015-08-07 19:40:45 +03001070 [IFLA_BR_VLAN_FILTERING] = { .type = NLA_U8 },
Toshiaki Makitad2d427b2015-08-27 15:32:26 +09001071 [IFLA_BR_VLAN_PROTOCOL] = { .type = NLA_U16 },
Nikolay Aleksandrov79102282015-10-04 14:23:28 +02001072 [IFLA_BR_GROUP_FWD_MASK] = { .type = NLA_U16 },
Nikolay Aleksandrov111189a2015-10-04 14:23:35 +02001073 [IFLA_BR_GROUP_ADDR] = { .type = NLA_BINARY,
1074 .len = ETH_ALEN },
Nikolay Aleksandrova9a6bc72015-10-04 14:23:37 +02001075 [IFLA_BR_MCAST_ROUTER] = { .type = NLA_U8 },
Nikolay Aleksandrov89126322015-10-04 14:23:38 +02001076 [IFLA_BR_MCAST_SNOOPING] = { .type = NLA_U8 },
Nikolay Aleksandrov295141d2015-10-04 14:23:39 +02001077 [IFLA_BR_MCAST_QUERY_USE_IFADDR] = { .type = NLA_U8 },
Nikolay Aleksandrovba062d7c2015-10-04 14:23:40 +02001078 [IFLA_BR_MCAST_QUERIER] = { .type = NLA_U8 },
Nikolay Aleksandrov431db3c2015-10-04 14:23:41 +02001079 [IFLA_BR_MCAST_HASH_ELASTICITY] = { .type = NLA_U32 },
Nikolay Aleksandrov858079f2015-10-04 14:23:42 +02001080 [IFLA_BR_MCAST_HASH_MAX] = { .type = NLA_U32 },
Nikolay Aleksandrov79b859f2015-10-04 14:23:43 +02001081 [IFLA_BR_MCAST_LAST_MEMBER_CNT] = { .type = NLA_U32 },
Nikolay Aleksandrovb89e6ba2015-10-04 14:23:44 +02001082 [IFLA_BR_MCAST_STARTUP_QUERY_CNT] = { .type = NLA_U32 },
Nikolay Aleksandrov7e4df512015-10-04 14:23:45 +02001083 [IFLA_BR_MCAST_LAST_MEMBER_INTVL] = { .type = NLA_U64 },
1084 [IFLA_BR_MCAST_MEMBERSHIP_INTVL] = { .type = NLA_U64 },
1085 [IFLA_BR_MCAST_QUERIER_INTVL] = { .type = NLA_U64 },
1086 [IFLA_BR_MCAST_QUERY_INTVL] = { .type = NLA_U64 },
1087 [IFLA_BR_MCAST_QUERY_RESPONSE_INTVL] = { .type = NLA_U64 },
1088 [IFLA_BR_MCAST_STARTUP_QUERY_INTVL] = { .type = NLA_U64 },
Nikolay Aleksandrov93870cc2015-10-04 14:23:46 +02001089 [IFLA_BR_NF_CALL_IPTABLES] = { .type = NLA_U8 },
1090 [IFLA_BR_NF_CALL_IP6TABLES] = { .type = NLA_U8 },
1091 [IFLA_BR_NF_CALL_ARPTABLES] = { .type = NLA_U8 },
Nikolay Aleksandrov0f963b72015-10-04 14:23:47 +02001092 [IFLA_BR_VLAN_DEFAULT_PVID] = { .type = NLA_U16 },
Nikolay Aleksandrov6dada9b2016-04-30 10:25:28 +02001093 [IFLA_BR_VLAN_STATS_ENABLED] = { .type = NLA_U8 },
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001094 [IFLA_BR_MCAST_STATS_ENABLED] = { .type = NLA_U8 },
Nikolay Aleksandrov5e923582016-11-21 13:03:24 +01001095 [IFLA_BR_MCAST_IGMP_VERSION] = { .type = NLA_U8 },
Nikolay Aleksandrovaa2ae3e2016-11-21 13:03:25 +01001096 [IFLA_BR_MCAST_MLD_VERSION] = { .type = NLA_U8 },
Nikolay Aleksandrov9163a0f2018-10-12 13:41:16 +03001097 [IFLA_BR_VLAN_STATS_PER_PORT] = { .type = NLA_U8 },
Johannes Berg81408602020-08-18 10:17:31 +02001098 [IFLA_BR_MULTI_BOOLOPT] =
1099 NLA_POLICY_EXACT_LEN(sizeof(struct br_boolopt_multi)),
Jiri Pirko13323512014-09-05 15:51:32 +02001100};
1101
1102static int br_changelink(struct net_device *brdev, struct nlattr *tb[],
Matthias Schifferad744b22017-06-25 23:56:00 +02001103 struct nlattr *data[],
1104 struct netlink_ext_ack *extack)
Jiri Pirko13323512014-09-05 15:51:32 +02001105{
1106 struct net_bridge *br = netdev_priv(brdev);
1107 int err;
1108
1109 if (!data)
1110 return 0;
1111
1112 if (data[IFLA_BR_FORWARD_DELAY]) {
1113 err = br_set_forward_delay(br, nla_get_u32(data[IFLA_BR_FORWARD_DELAY]));
1114 if (err)
1115 return err;
1116 }
1117
1118 if (data[IFLA_BR_HELLO_TIME]) {
1119 err = br_set_hello_time(br, nla_get_u32(data[IFLA_BR_HELLO_TIME]));
1120 if (err)
1121 return err;
1122 }
1123
1124 if (data[IFLA_BR_MAX_AGE]) {
1125 err = br_set_max_age(br, nla_get_u32(data[IFLA_BR_MAX_AGE]));
1126 if (err)
1127 return err;
1128 }
1129
Jörg Thalheimaf615762015-03-18 10:06:58 +01001130 if (data[IFLA_BR_AGEING_TIME]) {
Scott Feldmanc62987b2015-10-08 19:23:19 -07001131 err = br_set_ageing_time(br, nla_get_u32(data[IFLA_BR_AGEING_TIME]));
1132 if (err)
1133 return err;
Jörg Thalheimaf615762015-03-18 10:06:58 +01001134 }
1135
1136 if (data[IFLA_BR_STP_STATE]) {
1137 u32 stp_enabled = nla_get_u32(data[IFLA_BR_STP_STATE]);
1138
Horatiu Vultur419dba8a2020-04-26 15:22:08 +02001139 err = br_stp_set_enabled(br, stp_enabled, extack);
1140 if (err)
1141 return err;
Jörg Thalheimaf615762015-03-18 10:06:58 +01001142 }
1143
1144 if (data[IFLA_BR_PRIORITY]) {
1145 u32 priority = nla_get_u16(data[IFLA_BR_PRIORITY]);
1146
1147 br_stp_set_bridge_priority(br, priority);
1148 }
1149
Nikolay Aleksandrova7854032015-08-07 19:40:45 +03001150 if (data[IFLA_BR_VLAN_FILTERING]) {
1151 u8 vlan_filter = nla_get_u8(data[IFLA_BR_VLAN_FILTERING]);
1152
1153 err = __br_vlan_filter_toggle(br, vlan_filter);
1154 if (err)
1155 return err;
1156 }
1157
Toshiaki Makitad2d427b2015-08-27 15:32:26 +09001158#ifdef CONFIG_BRIDGE_VLAN_FILTERING
1159 if (data[IFLA_BR_VLAN_PROTOCOL]) {
1160 __be16 vlan_proto = nla_get_be16(data[IFLA_BR_VLAN_PROTOCOL]);
1161
1162 err = __br_vlan_set_proto(br, vlan_proto);
1163 if (err)
1164 return err;
1165 }
Nikolay Aleksandrov0f963b72015-10-04 14:23:47 +02001166
1167 if (data[IFLA_BR_VLAN_DEFAULT_PVID]) {
1168 __u16 defpvid = nla_get_u16(data[IFLA_BR_VLAN_DEFAULT_PVID]);
1169
Petr Machata169327d2018-12-12 17:02:50 +00001170 err = __br_vlan_set_default_pvid(br, defpvid, extack);
Nikolay Aleksandrov0f963b72015-10-04 14:23:47 +02001171 if (err)
1172 return err;
1173 }
Nikolay Aleksandrov6dada9b2016-04-30 10:25:28 +02001174
1175 if (data[IFLA_BR_VLAN_STATS_ENABLED]) {
1176 __u8 vlan_stats = nla_get_u8(data[IFLA_BR_VLAN_STATS_ENABLED]);
1177
1178 err = br_vlan_set_stats(br, vlan_stats);
1179 if (err)
1180 return err;
1181 }
Nikolay Aleksandrov9163a0f2018-10-12 13:41:16 +03001182
1183 if (data[IFLA_BR_VLAN_STATS_PER_PORT]) {
1184 __u8 per_port = nla_get_u8(data[IFLA_BR_VLAN_STATS_PER_PORT]);
1185
1186 err = br_vlan_set_stats_per_port(br, per_port);
1187 if (err)
1188 return err;
1189 }
Toshiaki Makitad2d427b2015-08-27 15:32:26 +09001190#endif
1191
Nikolay Aleksandrov79102282015-10-04 14:23:28 +02001192 if (data[IFLA_BR_GROUP_FWD_MASK]) {
1193 u16 fwd_mask = nla_get_u16(data[IFLA_BR_GROUP_FWD_MASK]);
1194
1195 if (fwd_mask & BR_GROUPFWD_RESTRICTED)
1196 return -EINVAL;
1197 br->group_fwd_mask = fwd_mask;
1198 }
1199
Nikolay Aleksandrov111189a2015-10-04 14:23:35 +02001200 if (data[IFLA_BR_GROUP_ADDR]) {
1201 u8 new_addr[ETH_ALEN];
1202
1203 if (nla_len(data[IFLA_BR_GROUP_ADDR]) != ETH_ALEN)
1204 return -EINVAL;
1205 memcpy(new_addr, nla_data(data[IFLA_BR_GROUP_ADDR]), ETH_ALEN);
1206 if (!is_link_local_ether_addr(new_addr))
1207 return -EINVAL;
1208 if (new_addr[5] == 1 || /* 802.3x Pause address */
1209 new_addr[5] == 2 || /* 802.3ad Slow protocols */
1210 new_addr[5] == 3) /* 802.1X PAE address */
1211 return -EINVAL;
1212 spin_lock_bh(&br->lock);
1213 memcpy(br->group_addr, new_addr, sizeof(br->group_addr));
1214 spin_unlock_bh(&br->lock);
Nikolay Aleksandrovbe3664a2018-09-26 17:01:02 +03001215 br_opt_toggle(br, BROPT_GROUP_ADDR_SET, true);
Nikolay Aleksandrov111189a2015-10-04 14:23:35 +02001216 br_recalculate_fwd_mask(br);
1217 }
1218
Nikolay Aleksandrov150217c2015-10-04 14:23:36 +02001219 if (data[IFLA_BR_FDB_FLUSH])
1220 br_fdb_flush(br);
1221
Nikolay Aleksandrova9a6bc72015-10-04 14:23:37 +02001222#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
1223 if (data[IFLA_BR_MCAST_ROUTER]) {
1224 u8 multicast_router = nla_get_u8(data[IFLA_BR_MCAST_ROUTER]);
1225
1226 err = br_multicast_set_router(br, multicast_router);
1227 if (err)
1228 return err;
1229 }
Nikolay Aleksandrov89126322015-10-04 14:23:38 +02001230
1231 if (data[IFLA_BR_MCAST_SNOOPING]) {
1232 u8 mcast_snooping = nla_get_u8(data[IFLA_BR_MCAST_SNOOPING]);
1233
YueHaibinga26d94b2018-12-17 17:46:23 +08001234 br_multicast_toggle(br, mcast_snooping);
Nikolay Aleksandrov89126322015-10-04 14:23:38 +02001235 }
Nikolay Aleksandrov295141d2015-10-04 14:23:39 +02001236
1237 if (data[IFLA_BR_MCAST_QUERY_USE_IFADDR]) {
1238 u8 val;
1239
1240 val = nla_get_u8(data[IFLA_BR_MCAST_QUERY_USE_IFADDR]);
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +03001241 br_opt_toggle(br, BROPT_MULTICAST_QUERY_USE_IFADDR, !!val);
Nikolay Aleksandrov295141d2015-10-04 14:23:39 +02001242 }
Nikolay Aleksandrovba062d7c2015-10-04 14:23:40 +02001243
1244 if (data[IFLA_BR_MCAST_QUERIER]) {
1245 u8 mcast_querier = nla_get_u8(data[IFLA_BR_MCAST_QUERIER]);
1246
1247 err = br_multicast_set_querier(br, mcast_querier);
1248 if (err)
1249 return err;
1250 }
Nikolay Aleksandrov431db3c2015-10-04 14:23:41 +02001251
Nikolay Aleksandrovcf332bca2018-12-05 15:14:26 +02001252 if (data[IFLA_BR_MCAST_HASH_ELASTICITY])
1253 br_warn(br, "the hash_elasticity option has been deprecated and is always %u\n",
1254 RHT_ELASTICITY);
Nikolay Aleksandrov858079f2015-10-04 14:23:42 +02001255
Nikolay Aleksandrov19e3a9c2018-12-05 15:14:24 +02001256 if (data[IFLA_BR_MCAST_HASH_MAX])
1257 br->hash_max = nla_get_u32(data[IFLA_BR_MCAST_HASH_MAX]);
Nikolay Aleksandrov79b859f2015-10-04 14:23:43 +02001258
1259 if (data[IFLA_BR_MCAST_LAST_MEMBER_CNT]) {
1260 u32 val = nla_get_u32(data[IFLA_BR_MCAST_LAST_MEMBER_CNT]);
1261
1262 br->multicast_last_member_count = val;
1263 }
Nikolay Aleksandrovb89e6ba2015-10-04 14:23:44 +02001264
1265 if (data[IFLA_BR_MCAST_STARTUP_QUERY_CNT]) {
1266 u32 val = nla_get_u32(data[IFLA_BR_MCAST_STARTUP_QUERY_CNT]);
1267
1268 br->multicast_startup_query_count = val;
1269 }
Nikolay Aleksandrov7e4df512015-10-04 14:23:45 +02001270
1271 if (data[IFLA_BR_MCAST_LAST_MEMBER_INTVL]) {
1272 u64 val = nla_get_u64(data[IFLA_BR_MCAST_LAST_MEMBER_INTVL]);
1273
1274 br->multicast_last_member_interval = clock_t_to_jiffies(val);
1275 }
1276
1277 if (data[IFLA_BR_MCAST_MEMBERSHIP_INTVL]) {
1278 u64 val = nla_get_u64(data[IFLA_BR_MCAST_MEMBERSHIP_INTVL]);
1279
1280 br->multicast_membership_interval = clock_t_to_jiffies(val);
1281 }
1282
1283 if (data[IFLA_BR_MCAST_QUERIER_INTVL]) {
1284 u64 val = nla_get_u64(data[IFLA_BR_MCAST_QUERIER_INTVL]);
1285
1286 br->multicast_querier_interval = clock_t_to_jiffies(val);
1287 }
1288
1289 if (data[IFLA_BR_MCAST_QUERY_INTVL]) {
1290 u64 val = nla_get_u64(data[IFLA_BR_MCAST_QUERY_INTVL]);
1291
1292 br->multicast_query_interval = clock_t_to_jiffies(val);
1293 }
1294
1295 if (data[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]) {
1296 u64 val = nla_get_u64(data[IFLA_BR_MCAST_QUERY_RESPONSE_INTVL]);
1297
1298 br->multicast_query_response_interval = clock_t_to_jiffies(val);
1299 }
1300
1301 if (data[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]) {
1302 u64 val = nla_get_u64(data[IFLA_BR_MCAST_STARTUP_QUERY_INTVL]);
1303
1304 br->multicast_startup_query_interval = clock_t_to_jiffies(val);
1305 }
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001306
1307 if (data[IFLA_BR_MCAST_STATS_ENABLED]) {
1308 __u8 mcast_stats;
1309
1310 mcast_stats = nla_get_u8(data[IFLA_BR_MCAST_STATS_ENABLED]);
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +03001311 br_opt_toggle(br, BROPT_MULTICAST_STATS_ENABLED, !!mcast_stats);
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001312 }
Nikolay Aleksandrov5e923582016-11-21 13:03:24 +01001313
1314 if (data[IFLA_BR_MCAST_IGMP_VERSION]) {
1315 __u8 igmp_version;
1316
1317 igmp_version = nla_get_u8(data[IFLA_BR_MCAST_IGMP_VERSION]);
1318 err = br_multicast_set_igmp_version(br, igmp_version);
1319 if (err)
1320 return err;
1321 }
Nikolay Aleksandrovaa2ae3e2016-11-21 13:03:25 +01001322
1323#if IS_ENABLED(CONFIG_IPV6)
1324 if (data[IFLA_BR_MCAST_MLD_VERSION]) {
1325 __u8 mld_version;
1326
1327 mld_version = nla_get_u8(data[IFLA_BR_MCAST_MLD_VERSION]);
1328 err = br_multicast_set_mld_version(br, mld_version);
1329 if (err)
1330 return err;
1331 }
1332#endif
Nikolay Aleksandrova9a6bc72015-10-04 14:23:37 +02001333#endif
Nikolay Aleksandrov93870cc2015-10-04 14:23:46 +02001334#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
1335 if (data[IFLA_BR_NF_CALL_IPTABLES]) {
1336 u8 val = nla_get_u8(data[IFLA_BR_NF_CALL_IPTABLES]);
1337
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +03001338 br_opt_toggle(br, BROPT_NF_CALL_IPTABLES, !!val);
Nikolay Aleksandrov93870cc2015-10-04 14:23:46 +02001339 }
1340
1341 if (data[IFLA_BR_NF_CALL_IP6TABLES]) {
1342 u8 val = nla_get_u8(data[IFLA_BR_NF_CALL_IP6TABLES]);
1343
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +03001344 br_opt_toggle(br, BROPT_NF_CALL_IP6TABLES, !!val);
Nikolay Aleksandrov93870cc2015-10-04 14:23:46 +02001345 }
1346
1347 if (data[IFLA_BR_NF_CALL_ARPTABLES]) {
1348 u8 val = nla_get_u8(data[IFLA_BR_NF_CALL_ARPTABLES]);
1349
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +03001350 br_opt_toggle(br, BROPT_NF_CALL_ARPTABLES, !!val);
Nikolay Aleksandrov93870cc2015-10-04 14:23:46 +02001351 }
1352#endif
Nikolay Aleksandrova9a6bc72015-10-04 14:23:37 +02001353
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +02001354 if (data[IFLA_BR_MULTI_BOOLOPT]) {
1355 struct br_boolopt_multi *bm;
1356
1357 bm = nla_data(data[IFLA_BR_MULTI_BOOLOPT]);
1358 err = br_boolopt_multi_toggle(br, bm, extack);
1359 if (err)
1360 return err;
1361 }
1362
Jiri Pirko13323512014-09-05 15:51:32 +02001363 return 0;
1364}
1365
Ivan Vecerab6677442017-01-20 18:12:17 +01001366static int br_dev_newlink(struct net *src_net, struct net_device *dev,
Matthias Schiffer7a3f4a12017-06-25 23:55:59 +02001367 struct nlattr *tb[], struct nlattr *data[],
1368 struct netlink_ext_ack *extack)
Ivan Vecerab6677442017-01-20 18:12:17 +01001369{
1370 struct net_bridge *br = netdev_priv(dev);
1371 int err;
1372
Nikolay Aleksandrov84aeb432017-12-18 17:35:09 +02001373 err = register_netdevice(dev);
1374 if (err)
1375 return err;
1376
Ivan Vecerab6677442017-01-20 18:12:17 +01001377 if (tb[IFLA_ADDRESS]) {
1378 spin_lock_bh(&br->lock);
1379 br_stp_change_bridge_id(br, nla_data(tb[IFLA_ADDRESS]));
1380 spin_unlock_bh(&br->lock);
1381 }
1382
Matthias Schifferad744b22017-06-25 23:56:00 +02001383 err = br_changelink(dev, tb, data, extack);
Ido Schimmel5b8d5422017-04-10 14:59:28 +03001384 if (err)
Nikolay Aleksandrov84aeb432017-12-18 17:35:09 +02001385 br_dev_delete(dev, NULL);
1386
Ido Schimmel5b8d5422017-04-10 14:59:28 +03001387 return err;
Ivan Vecerab6677442017-01-20 18:12:17 +01001388}
1389
Jiri Pirkoe5c3ea52014-09-05 15:51:31 +02001390static size_t br_get_size(const struct net_device *brdev)
1391{
1392 return nla_total_size(sizeof(u32)) + /* IFLA_BR_FORWARD_DELAY */
1393 nla_total_size(sizeof(u32)) + /* IFLA_BR_HELLO_TIME */
1394 nla_total_size(sizeof(u32)) + /* IFLA_BR_MAX_AGE */
Jörg Thalheimaf615762015-03-18 10:06:58 +01001395 nla_total_size(sizeof(u32)) + /* IFLA_BR_AGEING_TIME */
1396 nla_total_size(sizeof(u32)) + /* IFLA_BR_STP_STATE */
1397 nla_total_size(sizeof(u16)) + /* IFLA_BR_PRIORITY */
Nikolay Aleksandrova7854032015-08-07 19:40:45 +03001398 nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_FILTERING */
Toshiaki Makitad2d427b2015-08-27 15:32:26 +09001399#ifdef CONFIG_BRIDGE_VLAN_FILTERING
1400 nla_total_size(sizeof(__be16)) + /* IFLA_BR_VLAN_PROTOCOL */
Nikolay Aleksandrov0f963b72015-10-04 14:23:47 +02001401 nla_total_size(sizeof(u16)) + /* IFLA_BR_VLAN_DEFAULT_PVID */
Nikolay Aleksandrov6dada9b2016-04-30 10:25:28 +02001402 nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_STATS_ENABLED */
Nikolay Aleksandrov9163a0f2018-10-12 13:41:16 +03001403 nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_STATS_PER_PORT */
Toshiaki Makitad2d427b2015-08-27 15:32:26 +09001404#endif
Nikolay Aleksandrov79102282015-10-04 14:23:28 +02001405 nla_total_size(sizeof(u16)) + /* IFLA_BR_GROUP_FWD_MASK */
Nikolay Aleksandrov5127c812015-10-04 14:23:29 +02001406 nla_total_size(sizeof(struct ifla_bridge_id)) + /* IFLA_BR_ROOT_ID */
Nikolay Aleksandrov7599a222015-10-04 14:23:30 +02001407 nla_total_size(sizeof(struct ifla_bridge_id)) + /* IFLA_BR_BRIDGE_ID */
Nikolay Aleksandrov8762ba62015-10-04 14:23:31 +02001408 nla_total_size(sizeof(u16)) + /* IFLA_BR_ROOT_PORT */
Nikolay Aleksandrov684dd242015-10-04 14:23:32 +02001409 nla_total_size(sizeof(u32)) + /* IFLA_BR_ROOT_PATH_COST */
Nikolay Aleksandrovb89e6ba2015-10-04 14:23:44 +02001410 nla_total_size(sizeof(u8)) + /* IFLA_BR_TOPOLOGY_CHANGE */
1411 nla_total_size(sizeof(u8)) + /* IFLA_BR_TOPOLOGY_CHANGE_DETECTED */
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001412 nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_HELLO_TIMER */
1413 nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_TCN_TIMER */
1414 nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_TOPOLOGY_CHANGE_TIMER */
1415 nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_GC_TIMER */
Nikolay Aleksandrov111189a2015-10-04 14:23:35 +02001416 nla_total_size(ETH_ALEN) + /* IFLA_BR_GROUP_ADDR */
Nikolay Aleksandrova9a6bc72015-10-04 14:23:37 +02001417#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
1418 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_ROUTER */
Nikolay Aleksandrov89126322015-10-04 14:23:38 +02001419 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_SNOOPING */
Nikolay Aleksandrov295141d2015-10-04 14:23:39 +02001420 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_QUERY_USE_IFADDR */
Nikolay Aleksandrovba062d7c2015-10-04 14:23:40 +02001421 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_QUERIER */
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001422 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_STATS_ENABLED */
Nikolay Aleksandrovb89e6ba2015-10-04 14:23:44 +02001423 nla_total_size(sizeof(u32)) + /* IFLA_BR_MCAST_HASH_ELASTICITY */
1424 nla_total_size(sizeof(u32)) + /* IFLA_BR_MCAST_HASH_MAX */
1425 nla_total_size(sizeof(u32)) + /* IFLA_BR_MCAST_LAST_MEMBER_CNT */
1426 nla_total_size(sizeof(u32)) + /* IFLA_BR_MCAST_STARTUP_QUERY_CNT */
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001427 nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_MCAST_LAST_MEMBER_INTVL */
1428 nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_MCAST_MEMBERSHIP_INTVL */
1429 nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_MCAST_QUERIER_INTVL */
1430 nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_MCAST_QUERY_INTVL */
1431 nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_MCAST_QUERY_RESPONSE_INTVL */
1432 nla_total_size_64bit(sizeof(u64)) + /* IFLA_BR_MCAST_STARTUP_QUERY_INTVL */
Nikolay Aleksandrov5e923582016-11-21 13:03:24 +01001433 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_IGMP_VERSION */
Nikolay Aleksandrovaa2ae3e2016-11-21 13:03:25 +01001434 nla_total_size(sizeof(u8)) + /* IFLA_BR_MCAST_MLD_VERSION */
Nikolay Aleksandrova9a6bc72015-10-04 14:23:37 +02001435#endif
Nikolay Aleksandrov93870cc2015-10-04 14:23:46 +02001436#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
1437 nla_total_size(sizeof(u8)) + /* IFLA_BR_NF_CALL_IPTABLES */
1438 nla_total_size(sizeof(u8)) + /* IFLA_BR_NF_CALL_IP6TABLES */
1439 nla_total_size(sizeof(u8)) + /* IFLA_BR_NF_CALL_ARPTABLES */
1440#endif
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +02001441 nla_total_size(sizeof(struct br_boolopt_multi)) + /* IFLA_BR_MULTI_BOOLOPT */
Jiri Pirkoe5c3ea52014-09-05 15:51:31 +02001442 0;
1443}
1444
1445static int br_fill_info(struct sk_buff *skb, const struct net_device *brdev)
1446{
1447 struct net_bridge *br = netdev_priv(brdev);
1448 u32 forward_delay = jiffies_to_clock_t(br->forward_delay);
1449 u32 hello_time = jiffies_to_clock_t(br->hello_time);
1450 u32 age_time = jiffies_to_clock_t(br->max_age);
Jörg Thalheimaf615762015-03-18 10:06:58 +01001451 u32 ageing_time = jiffies_to_clock_t(br->ageing_time);
1452 u32 stp_enabled = br->stp_enabled;
1453 u16 priority = (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1];
Ido Schimmel1f514452017-05-26 08:37:23 +02001454 u8 vlan_enabled = br_vlan_enabled(br->dev);
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +02001455 struct br_boolopt_multi bm;
Nikolay Aleksandrov4917a152015-10-05 12:11:21 +02001456 u64 clockval;
Nikolay Aleksandrov5127c812015-10-04 14:23:29 +02001457
Nikolay Aleksandrov4917a152015-10-05 12:11:21 +02001458 clockval = br_timer_value(&br->hello_timer);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001459 if (nla_put_u64_64bit(skb, IFLA_BR_HELLO_TIMER, clockval, IFLA_BR_PAD))
Nikolay Aleksandrov4917a152015-10-05 12:11:21 +02001460 return -EMSGSIZE;
1461 clockval = br_timer_value(&br->tcn_timer);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001462 if (nla_put_u64_64bit(skb, IFLA_BR_TCN_TIMER, clockval, IFLA_BR_PAD))
Nikolay Aleksandrov4917a152015-10-05 12:11:21 +02001463 return -EMSGSIZE;
1464 clockval = br_timer_value(&br->topology_change_timer);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001465 if (nla_put_u64_64bit(skb, IFLA_BR_TOPOLOGY_CHANGE_TIMER, clockval,
1466 IFLA_BR_PAD))
Nikolay Aleksandrov4917a152015-10-05 12:11:21 +02001467 return -EMSGSIZE;
Nikolay Aleksandrovf7cdee82017-02-04 18:05:07 +01001468 clockval = br_timer_value(&br->gc_work.timer);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001469 if (nla_put_u64_64bit(skb, IFLA_BR_GC_TIMER, clockval, IFLA_BR_PAD))
Nikolay Aleksandrov4917a152015-10-05 12:11:21 +02001470 return -EMSGSIZE;
Jiri Pirkoe5c3ea52014-09-05 15:51:31 +02001471
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +02001472 br_boolopt_multi_get(br, &bm);
Jiri Pirkoe5c3ea52014-09-05 15:51:31 +02001473 if (nla_put_u32(skb, IFLA_BR_FORWARD_DELAY, forward_delay) ||
1474 nla_put_u32(skb, IFLA_BR_HELLO_TIME, hello_time) ||
Jörg Thalheimaf615762015-03-18 10:06:58 +01001475 nla_put_u32(skb, IFLA_BR_MAX_AGE, age_time) ||
1476 nla_put_u32(skb, IFLA_BR_AGEING_TIME, ageing_time) ||
1477 nla_put_u32(skb, IFLA_BR_STP_STATE, stp_enabled) ||
Nikolay Aleksandrova7854032015-08-07 19:40:45 +03001478 nla_put_u16(skb, IFLA_BR_PRIORITY, priority) ||
Nikolay Aleksandrov79102282015-10-04 14:23:28 +02001479 nla_put_u8(skb, IFLA_BR_VLAN_FILTERING, vlan_enabled) ||
Nikolay Aleksandrov4917a152015-10-05 12:11:21 +02001480 nla_put_u16(skb, IFLA_BR_GROUP_FWD_MASK, br->group_fwd_mask) ||
1481 nla_put(skb, IFLA_BR_BRIDGE_ID, sizeof(struct ifla_bridge_id),
1482 &br->bridge_id) ||
1483 nla_put(skb, IFLA_BR_ROOT_ID, sizeof(struct ifla_bridge_id),
1484 &br->designated_root) ||
Nikolay Aleksandrov684dd242015-10-04 14:23:32 +02001485 nla_put_u16(skb, IFLA_BR_ROOT_PORT, br->root_port) ||
Nikolay Aleksandroved416302015-10-04 14:23:33 +02001486 nla_put_u32(skb, IFLA_BR_ROOT_PATH_COST, br->root_path_cost) ||
1487 nla_put_u8(skb, IFLA_BR_TOPOLOGY_CHANGE, br->topology_change) ||
1488 nla_put_u8(skb, IFLA_BR_TOPOLOGY_CHANGE_DETECTED,
Nikolay Aleksandrovd76bd142015-10-04 14:23:34 +02001489 br->topology_change_detected) ||
Nikolay Aleksandrova428afe2018-11-24 04:34:20 +02001490 nla_put(skb, IFLA_BR_GROUP_ADDR, ETH_ALEN, br->group_addr) ||
1491 nla_put(skb, IFLA_BR_MULTI_BOOLOPT, sizeof(bm), &bm))
Jiri Pirkoe5c3ea52014-09-05 15:51:31 +02001492 return -EMSGSIZE;
1493
Toshiaki Makitad2d427b2015-08-27 15:32:26 +09001494#ifdef CONFIG_BRIDGE_VLAN_FILTERING
Nikolay Aleksandrov0f963b72015-10-04 14:23:47 +02001495 if (nla_put_be16(skb, IFLA_BR_VLAN_PROTOCOL, br->vlan_proto) ||
Nikolay Aleksandrov6dada9b2016-04-30 10:25:28 +02001496 nla_put_u16(skb, IFLA_BR_VLAN_DEFAULT_PVID, br->default_pvid) ||
Nikolay Aleksandrovae757672018-09-26 17:01:00 +03001497 nla_put_u8(skb, IFLA_BR_VLAN_STATS_ENABLED,
Nikolay Aleksandrov9163a0f2018-10-12 13:41:16 +03001498 br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) ||
1499 nla_put_u8(skb, IFLA_BR_VLAN_STATS_PER_PORT,
Nikolay Aleksandrov600bea72019-04-16 16:15:56 +03001500 br_opt_get(br, BROPT_VLAN_STATS_PER_PORT)))
Toshiaki Makitad2d427b2015-08-27 15:32:26 +09001501 return -EMSGSIZE;
1502#endif
Nikolay Aleksandrova9a6bc72015-10-04 14:23:37 +02001503#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
Nikolay Aleksandrov89126322015-10-04 14:23:38 +02001504 if (nla_put_u8(skb, IFLA_BR_MCAST_ROUTER, br->multicast_router) ||
Nikolay Aleksandrov13cefad2018-09-26 17:01:03 +03001505 nla_put_u8(skb, IFLA_BR_MCAST_SNOOPING,
1506 br_opt_get(br, BROPT_MULTICAST_ENABLED)) ||
Nikolay Aleksandrov295141d2015-10-04 14:23:39 +02001507 nla_put_u8(skb, IFLA_BR_MCAST_QUERY_USE_IFADDR,
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +03001508 br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR)) ||
1509 nla_put_u8(skb, IFLA_BR_MCAST_QUERIER,
1510 br_opt_get(br, BROPT_MULTICAST_QUERIER)) ||
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001511 nla_put_u8(skb, IFLA_BR_MCAST_STATS_ENABLED,
Nikolay Aleksandrov675779a2018-09-26 17:01:04 +03001512 br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)) ||
Nikolay Aleksandrovcf332bca2018-12-05 15:14:26 +02001513 nla_put_u32(skb, IFLA_BR_MCAST_HASH_ELASTICITY, RHT_ELASTICITY) ||
Nikolay Aleksandrov79b859f2015-10-04 14:23:43 +02001514 nla_put_u32(skb, IFLA_BR_MCAST_HASH_MAX, br->hash_max) ||
1515 nla_put_u32(skb, IFLA_BR_MCAST_LAST_MEMBER_CNT,
Nikolay Aleksandrovb89e6ba2015-10-04 14:23:44 +02001516 br->multicast_last_member_count) ||
1517 nla_put_u32(skb, IFLA_BR_MCAST_STARTUP_QUERY_CNT,
Nikolay Aleksandrov5e923582016-11-21 13:03:24 +01001518 br->multicast_startup_query_count) ||
1519 nla_put_u8(skb, IFLA_BR_MCAST_IGMP_VERSION,
1520 br->multicast_igmp_version))
Nikolay Aleksandrova9a6bc72015-10-04 14:23:37 +02001521 return -EMSGSIZE;
Nikolay Aleksandrovaa2ae3e2016-11-21 13:03:25 +01001522#if IS_ENABLED(CONFIG_IPV6)
1523 if (nla_put_u8(skb, IFLA_BR_MCAST_MLD_VERSION,
1524 br->multicast_mld_version))
1525 return -EMSGSIZE;
1526#endif
Nikolay Aleksandrov7e4df512015-10-04 14:23:45 +02001527 clockval = jiffies_to_clock_t(br->multicast_last_member_interval);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001528 if (nla_put_u64_64bit(skb, IFLA_BR_MCAST_LAST_MEMBER_INTVL, clockval,
1529 IFLA_BR_PAD))
Nikolay Aleksandrov7e4df512015-10-04 14:23:45 +02001530 return -EMSGSIZE;
1531 clockval = jiffies_to_clock_t(br->multicast_membership_interval);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001532 if (nla_put_u64_64bit(skb, IFLA_BR_MCAST_MEMBERSHIP_INTVL, clockval,
1533 IFLA_BR_PAD))
Nikolay Aleksandrov7e4df512015-10-04 14:23:45 +02001534 return -EMSGSIZE;
1535 clockval = jiffies_to_clock_t(br->multicast_querier_interval);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001536 if (nla_put_u64_64bit(skb, IFLA_BR_MCAST_QUERIER_INTVL, clockval,
1537 IFLA_BR_PAD))
Nikolay Aleksandrov7e4df512015-10-04 14:23:45 +02001538 return -EMSGSIZE;
1539 clockval = jiffies_to_clock_t(br->multicast_query_interval);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001540 if (nla_put_u64_64bit(skb, IFLA_BR_MCAST_QUERY_INTVL, clockval,
1541 IFLA_BR_PAD))
Nikolay Aleksandrov7e4df512015-10-04 14:23:45 +02001542 return -EMSGSIZE;
1543 clockval = jiffies_to_clock_t(br->multicast_query_response_interval);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001544 if (nla_put_u64_64bit(skb, IFLA_BR_MCAST_QUERY_RESPONSE_INTVL, clockval,
1545 IFLA_BR_PAD))
Nikolay Aleksandrov7e4df512015-10-04 14:23:45 +02001546 return -EMSGSIZE;
1547 clockval = jiffies_to_clock_t(br->multicast_startup_query_interval);
Nicolas Dichtel12a0faa2016-04-25 10:25:18 +02001548 if (nla_put_u64_64bit(skb, IFLA_BR_MCAST_STARTUP_QUERY_INTVL, clockval,
1549 IFLA_BR_PAD))
Nikolay Aleksandrov7e4df512015-10-04 14:23:45 +02001550 return -EMSGSIZE;
Nikolay Aleksandrova9a6bc72015-10-04 14:23:37 +02001551#endif
Nikolay Aleksandrov93870cc2015-10-04 14:23:46 +02001552#if IS_ENABLED(CONFIG_BRIDGE_NETFILTER)
1553 if (nla_put_u8(skb, IFLA_BR_NF_CALL_IPTABLES,
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +03001554 br_opt_get(br, BROPT_NF_CALL_IPTABLES) ? 1 : 0) ||
Nikolay Aleksandrov93870cc2015-10-04 14:23:46 +02001555 nla_put_u8(skb, IFLA_BR_NF_CALL_IP6TABLES,
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +03001556 br_opt_get(br, BROPT_NF_CALL_IP6TABLES) ? 1 : 0) ||
Nikolay Aleksandrov93870cc2015-10-04 14:23:46 +02001557 nla_put_u8(skb, IFLA_BR_NF_CALL_ARPTABLES,
Nikolay Aleksandrov8df35102018-09-26 17:01:01 +03001558 br_opt_get(br, BROPT_NF_CALL_ARPTABLES) ? 1 : 0))
Nikolay Aleksandrov93870cc2015-10-04 14:23:46 +02001559 return -EMSGSIZE;
1560#endif
Nikolay Aleksandrova9a6bc72015-10-04 14:23:37 +02001561
Jiri Pirkoe5c3ea52014-09-05 15:51:31 +02001562 return 0;
1563}
1564
Nikolay Aleksandrovd5ff8c42016-08-17 12:53:09 +02001565static size_t br_get_linkxstats_size(const struct net_device *dev, int attr)
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001566{
Nikolay Aleksandrovd5ff8c42016-08-17 12:53:09 +02001567 struct net_bridge_port *p = NULL;
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001568 struct net_bridge_vlan_group *vg;
1569 struct net_bridge_vlan *v;
Nikolay Aleksandrovd5ff8c42016-08-17 12:53:09 +02001570 struct net_bridge *br;
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001571 int numvls = 0;
1572
Nikolay Aleksandrovd5ff8c42016-08-17 12:53:09 +02001573 switch (attr) {
1574 case IFLA_STATS_LINK_XSTATS:
1575 br = netdev_priv(dev);
1576 vg = br_vlan_group(br);
1577 break;
1578 case IFLA_STATS_LINK_XSTATS_SLAVE:
1579 p = br_port_get_rtnl(dev);
1580 if (!p)
1581 return 0;
1582 br = p->br;
1583 vg = nbp_vlan_group(p);
1584 break;
1585 default:
1586 return 0;
1587 }
1588
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001589 if (vg) {
1590 /* we need to count all, even placeholder entries */
1591 list_for_each_entry(v, &vg->vlan_list, vlist)
1592 numvls++;
1593 }
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001594
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001595 return numvls * nla_total_size(sizeof(struct bridge_vlan_xstats)) +
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001596 nla_total_size(sizeof(struct br_mcast_stats)) +
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001597 nla_total_size(0);
1598}
1599
Nikolay Aleksandrovd5ff8c42016-08-17 12:53:09 +02001600static int br_fill_linkxstats(struct sk_buff *skb,
1601 const struct net_device *dev,
1602 int *prividx, int attr)
Nikolay Aleksandrov80e73cc2016-06-28 16:57:05 +02001603{
Nikolay Aleksandrovd5ff8c42016-08-17 12:53:09 +02001604 struct nlattr *nla __maybe_unused;
1605 struct net_bridge_port *p = NULL;
1606 struct net_bridge_vlan_group *vg;
1607 struct net_bridge_vlan *v;
1608 struct net_bridge *br;
1609 struct nlattr *nest;
1610 int vl_idx = 0;
Nikolay Aleksandrov80e73cc2016-06-28 16:57:05 +02001611
1612 switch (attr) {
1613 case IFLA_STATS_LINK_XSTATS:
Nikolay Aleksandrovd5ff8c42016-08-17 12:53:09 +02001614 br = netdev_priv(dev);
1615 vg = br_vlan_group(br);
Nikolay Aleksandrov80e73cc2016-06-28 16:57:05 +02001616 break;
1617 case IFLA_STATS_LINK_XSTATS_SLAVE:
Nikolay Aleksandrovd5ff8c42016-08-17 12:53:09 +02001618 p = br_port_get_rtnl(dev);
1619 if (!p)
1620 return 0;
1621 br = p->br;
1622 vg = nbp_vlan_group(p);
Nikolay Aleksandrov80e73cc2016-06-28 16:57:05 +02001623 break;
Nikolay Aleksandrovd5ff8c42016-08-17 12:53:09 +02001624 default:
1625 return -EINVAL;
Nikolay Aleksandrov80e73cc2016-06-28 16:57:05 +02001626 }
1627
Michal Kubecekae0be8d2019-04-26 11:13:06 +02001628 nest = nla_nest_start_noflag(skb, LINK_XSTATS_TYPE_BRIDGE);
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001629 if (!nest)
1630 return -EMSGSIZE;
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001631
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001632 if (vg) {
Nikolay Aleksandrov72f4af42016-08-25 14:27:51 +02001633 u16 pvid;
1634
1635 pvid = br_get_pvid(vg);
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001636 list_for_each_entry(v, &vg->vlan_list, vlist) {
1637 struct bridge_vlan_xstats vxi;
1638 struct br_vlan_stats stats;
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001639
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001640 if (++vl_idx < *prividx)
1641 continue;
1642 memset(&vxi, 0, sizeof(vxi));
1643 vxi.vid = v->vid;
Nikolay Aleksandrov61ba1a22016-08-17 12:53:10 +02001644 vxi.flags = v->flags;
Nikolay Aleksandrov72f4af42016-08-25 14:27:51 +02001645 if (v->vid == pvid)
1646 vxi.flags |= BRIDGE_VLAN_INFO_PVID;
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001647 br_vlan_get_stats(v, &stats);
1648 vxi.rx_bytes = stats.rx_bytes;
1649 vxi.rx_packets = stats.rx_packets;
1650 vxi.tx_bytes = stats.tx_bytes;
1651 vxi.tx_packets = stats.tx_packets;
1652
1653 if (nla_put(skb, BRIDGE_XSTATS_VLAN, sizeof(vxi), &vxi))
1654 goto nla_put_failure;
1655 }
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001656 }
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001657
1658#ifdef CONFIG_BRIDGE_IGMP_SNOOPING
1659 if (++vl_idx >= *prividx) {
1660 nla = nla_reserve_64bit(skb, BRIDGE_XSTATS_MCAST,
1661 sizeof(struct br_mcast_stats),
1662 BRIDGE_XSTATS_PAD);
1663 if (!nla)
1664 goto nla_put_failure;
Nikolay Aleksandrovd5ff8c42016-08-17 12:53:09 +02001665 br_multicast_get_stats(br, p, nla_data(nla));
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001666 }
1667#endif
Vivien Didelotde179962019-12-11 20:07:10 -05001668
1669 if (p) {
1670 nla = nla_reserve_64bit(skb, BRIDGE_XSTATS_STP,
1671 sizeof(p->stp_xstats),
1672 BRIDGE_XSTATS_PAD);
1673 if (!nla)
1674 goto nla_put_failure;
1675
1676 spin_lock_bh(&br->lock);
1677 memcpy(nla_data(nla), &p->stp_xstats, sizeof(p->stp_xstats));
1678 spin_unlock_bh(&br->lock);
1679 }
1680
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001681 nla_nest_end(skb, nest);
1682 *prividx = 0;
Nikolay Aleksandrov1080ab92016-06-28 16:57:06 +02001683
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001684 return 0;
1685
1686nla_put_failure:
1687 nla_nest_end(skb, nest);
1688 *prividx = vl_idx;
1689
1690 return -EMSGSIZE;
1691}
Roopa Prabhufed0a152015-02-25 23:55:40 -08001692
Daniel Borkmann207895fd32015-01-29 12:15:03 +01001693static struct rtnl_af_ops br_af_ops __read_mostly = {
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +00001694 .family = AF_BRIDGE,
Arad, Ronenb1974ed2015-10-19 09:23:28 -07001695 .get_link_af_size = br_get_link_af_size_filtered,
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +00001696};
1697
stephen hemminger149ddd82012-06-26 05:48:45 +00001698struct rtnl_link_ops br_link_ops __read_mostly = {
Jiri Pirkoced82832014-09-05 15:51:29 +02001699 .kind = "bridge",
1700 .priv_size = sizeof(struct net_bridge),
1701 .setup = br_dev_setup,
Scott Feldmaneb4cb852015-08-19 11:29:35 -07001702 .maxtype = IFLA_BR_MAX,
Jiri Pirko13323512014-09-05 15:51:32 +02001703 .policy = br_policy,
Jiri Pirkoced82832014-09-05 15:51:29 +02001704 .validate = br_validate,
1705 .newlink = br_dev_newlink,
Jiri Pirko13323512014-09-05 15:51:32 +02001706 .changelink = br_changelink,
Jiri Pirkoced82832014-09-05 15:51:29 +02001707 .dellink = br_dev_delete,
Jiri Pirkoe5c3ea52014-09-05 15:51:31 +02001708 .get_size = br_get_size,
1709 .fill_info = br_fill_info,
Nikolay Aleksandrova60c0902016-04-30 10:25:29 +02001710 .fill_linkxstats = br_fill_linkxstats,
1711 .get_linkxstats_size = br_get_linkxstats_size,
Jiri Pirko3ac636b2014-09-05 15:51:30 +02001712
1713 .slave_maxtype = IFLA_BRPORT_MAX,
1714 .slave_policy = br_port_policy,
1715 .slave_changelink = br_port_slave_changelink,
Jiri Pirkoced82832014-09-05 15:51:29 +02001716 .get_slave_size = br_port_get_slave_size,
1717 .fill_slave_info = br_port_fill_slave_info,
stephen hemmingerbb900b22011-04-04 14:03:32 +00001718};
1719
1720int __init br_netlink_init(void)
Stephen Hemminger11dc1f32006-05-25 16:00:12 -07001721{
Vlad Yasevich3ec8e9f2013-01-02 09:41:25 +00001722 int err;
1723
1724 br_mdb_init();
Nikolay Aleksandrov8dcea182020-01-14 19:56:09 +02001725 br_vlan_rtnl_init();
stephen hemminger3678a9d2013-12-30 10:41:32 -08001726 rtnl_af_register(&br_af_ops);
Vlad Yasevich3ec8e9f2013-01-02 09:41:25 +00001727
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +00001728 err = rtnl_link_register(&br_link_ops);
1729 if (err)
1730 goto out_af;
1731
Vlad Yasevich3ec8e9f2013-01-02 09:41:25 +00001732 return 0;
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +00001733
1734out_af:
1735 rtnl_af_unregister(&br_af_ops);
Vlad Yasevich3ec8e9f2013-01-02 09:41:25 +00001736 br_mdb_uninit();
1737 return err;
Stephen Hemminger11dc1f32006-05-25 16:00:12 -07001738}
1739
Pablo Neira Ayuso34666d42014-09-18 11:29:03 +02001740void br_netlink_fini(void)
stephen hemmingerbb900b22011-04-04 14:03:32 +00001741{
Vlad Yasevich3ec8e9f2013-01-02 09:41:25 +00001742 br_mdb_uninit();
Nikolay Aleksandrov8dcea182020-01-14 19:56:09 +02001743 br_vlan_rtnl_uninit();
Vlad Yasevich6cbdcee2013-02-13 12:00:13 +00001744 rtnl_af_unregister(&br_af_ops);
stephen hemmingerbb900b22011-04-04 14:03:32 +00001745 rtnl_link_unregister(&br_link_ops);
stephen hemmingerbb900b22011-04-04 14:03:32 +00001746}