Re: [Bridge] [PATCH net-next 1/2] net: bridge: add support for user-controlled bool options

2018-11-22 Thread Nikolay Aleksandrov
On 22/11/2018 18:13, Nikolay Aleksandrov wrote:

>>> +int br_boolopt_multi_toggle(struct net_bridge *br,
>>> +   struct br_boolopt_multi *bm)
>>> +{
>>> +   unsigned long bitmap = bm->optmask;
>>> +   int err = 0;
>>> +   int opt_id;
>>> +
>>> +   for_each_set_bit(opt_id, , BR_BOOLOPT_MAX) {
>>> +   bool on = !!(bm->optval & BIT(opt_id));
>>> +
>>> +   err = br_boolopt_toggle(br, opt_id, on);
>>> +   if (err) {
>>> +   br_debug(br, "boolopt multi-toggle error: option: %d 
>>> current: %d new: %d error: %d\n",
>>> +opt_id, br_boolopt_get(br, opt_id), on, err);
>>> +   break;
>>> +   }
>>
>> An old kernel with a new iproute2 might partially succeed in toggling
>> some low bits, but then silently ignore a high bit that is not
>> supported by the kernel. As a user, i want to know the kernel does not
>> support an option i'm trying to toggle.
>>
> 
> That is already how netlink option setting works, if the option isn't 
> supported
> it is silently ignored. I tried to stay as close to the current behaviour as 
> possible.
> It also applies to partial option changes, some options will be changed until 
> an error
> is encountered.
> 
>> Can you walk all the bits in the u32 from the MSB to the LSB? That
>> should avoid this problem.
>>
> 
> I did wonder about this and left it as netlink option behaviour but
> I can leave the walk as is and just check if the highest order set bit >= 
> BR_BOOLOPT_MAX
> and err out with ENOTSUPP for example. Will reconsider for v2.
> 

Actually this doesn't improve user experience, after testing a little the 
problem is
that we can't return to the user the exact option that failed in any 
understandable manner.
The options are:
 - exact error message: (no bit/option value) so pretty much just say "Failed 
bool option"
 - pr_err: this has 2 issues, first it can't be retrieved by the caller (will 
be in the logs)
   and more importantly the best we can do is print the option bit that 
we don't support
   which really doesn't help the user at all

So the example is having newer iproute2 on older kernel and trying to set 
non-existing option
mixed with existing ones - the user has no way of determining which one failed 
even if we print
the bit, so this is really frustrating. The current way of ignoring the missing 
options seems
a bit more user-friendly and also with the change that we return the supported 
bit options
in optmask (thanks for the suggestion), the user-space tool (iproute2) can 
determine if an
option is not supported and at least give an indication when dumping it.
All of this does align with how netlink currently handles options and people 
are used to it.





Re: [Bridge] [PATCH net-next 1/2] net: bridge: add support for user-controlled bool options

2018-11-22 Thread Stephen Hemminger
On Thu, 22 Nov 2018 18:01:29 +0200
Nikolay Aleksandrov  wrote:

> On 22/11/2018 17:35, Andrew Lunn wrote:
> > On Thu, Nov 22, 2018 at 06:29:24AM +0200, Nikolay Aleksandrov wrote:  
> >> We have been adding many new bridge options, a big number of which are
> >> boolean but still take up netlink attribute ids and waste space in the skb.
> >> Recently we discussed learning from link-local packets[1] and decided
> >> yet another new boolean option will be needed, thus introducing this API
> >> to save some bridge nl space.
> >> The API supports changing the value of multiple boolean options at once
> >> via the br_boolopt_multi struct which has an optmask (which options to
> >> set, bit per opt) and optval (options' new values). Future boolean
> >> options will only be added to the br_boolopt_id enum and then will have
> >> to be handled in br_boolopt_toggle/get. The API will automatically
> >> add the ability to change and export them via netlink, sysfs can use the
> >> single boolopt function versions to do the same. The behaviour with
> >> failing/succeeding is the same as with normal netlink option changing.
> >>
> >> If an option requires mapping to internal kernel flag or needs special
> >> configuration to be enabled then it should be handled in
> >> br_boolopt_toggle. It should also be able to retrieve an option's current
> >> state via br_boolopt_get.
> >>
> >> [1] https://www.spinics.net/lists/netdev/msg532698.html
> >>
> >> Signed-off-by: Nikolay Aleksandrov 
> >> ---
> >>  include/uapi/linux/if_bridge.h | 18 +
> >>  include/uapi/linux/if_link.h   |  1 +
> >>  net/bridge/br.c| 68 ++
> >>  net/bridge/br_netlink.c| 17 -
> >>  net/bridge/br_private.h|  6 +++
> >>  net/core/rtnetlink.c   |  2 +-
> >>  6 files changed, 110 insertions(+), 2 deletions(-)
> >>
> >> diff --git a/include/uapi/linux/if_bridge.h 
> >> b/include/uapi/linux/if_bridge.h
> >> index e41eda3c71f1..6dc02c03bdf8 100644
> >> --- a/include/uapi/linux/if_bridge.h
> >> +++ b/include/uapi/linux/if_bridge.h
> >> @@ -292,4 +292,22 @@ struct br_mcast_stats {
> >>__u64 mcast_bytes[BR_MCAST_DIR_SIZE];
> >>__u64 mcast_packets[BR_MCAST_DIR_SIZE];
> >>  };
> >> +
> >> +/* bridge boolean options
> >> + * IMPORTANT: if adding a new option do not forget to handle
> >> + *it in br_boolopt_toggle/get and bridge sysfs
> >> + */
> >> +enum br_boolopt_id {
> >> +  BR_BOOLOPT_MAX
> >> +};
> >> +
> >> +/* struct br_boolopt_multi - change multiple bridge boolean options
> >> + *
> >> + * @optval: new option values (bit per option)
> >> + * @optmask: options to change (bit per option)
> >> + */
> >> +struct br_boolopt_multi {
> >> +  __u32 optval;
> >> +  __u32 optmask;
> >> +};  
> > 
> > Hi Nikolay
> > 
> > Thanks for handling this.
> > 
> > How many boolean options do we already have? What it the likelihood a
> > u32 is going to be too small, in a couple of years time?
> >   
> 
> It would mean doubling the number of current options and this is only for
> boolean options so I think we're safe.
> 
> > I recently went through the pain of converting the u32 for
> > representing link modes in the phylib API to a linux bitmap.  I'm just
> > wondering if in the long run, using a linux bitmap right from the
> > beginning would be better?
> >   
> >> +int br_boolopt_multi_toggle(struct net_bridge *br,
> >> +  struct br_boolopt_multi *bm)
> >> +{
> >> +  unsigned long bitmap = bm->optmask;
> >> +  int err = 0;
> >> +  int opt_id;
> >> +
> >> +  for_each_set_bit(opt_id, , BR_BOOLOPT_MAX) {
> >> +  bool on = !!(bm->optval & BIT(opt_id));
> >> +
> >> +  err = br_boolopt_toggle(br, opt_id, on);
> >> +  if (err) {
> >> +  br_debug(br, "boolopt multi-toggle error: option: %d 
> >> current: %d new: %d error: %d\n",
> >> +   opt_id, br_boolopt_get(br, opt_id), on, err);  
> > 
> > Would it be possible to return that to userspace using the extended
> > error infrastructure?
> >   
> 
> No, it doesn't support dynamic messages AFAIK.
> 
> >   Andrew
> >   
> 

My concern is about backwards compatibility. What about old userspace and new 
userspace tools with old kernels.
Having multiple bits does allow handling cases where certain combos won't work.


Re: [Bridge] [PATCH net-next 1/2] net: bridge: add support for user-controlled bool options

2018-11-22 Thread Nikolay Aleksandrov
On 22/11/2018 17:49, Andrew Lunn wrote:
>> +/* br_boolopt_toggle - change user-controlled boolean option
>> + *
>> + * @br: bridge device
>> + * @opt: id of the option to change
>> + * @on: new option value
>> + *
>> + * Changes the value of the respective boolean option to @on taking care of
>> + * any internal option value mapping and configuration.
>> + */
>> +int br_boolopt_toggle(struct net_bridge *br, enum br_boolopt_id opt, bool 
>> on)
>> +{
>> +int err = -ENOENT;
>> +
>> +switch (opt) {
>> +default:
>> +break;
>> +}
>> +
>> +return err;
>> +}
>> +
> 
> 
>> +int br_boolopt_multi_toggle(struct net_bridge *br,
>> +struct br_boolopt_multi *bm)
>> +{
>> +unsigned long bitmap = bm->optmask;
>> +int err = 0;
>> +int opt_id;
>> +
>> +for_each_set_bit(opt_id, , BR_BOOLOPT_MAX) {
>> +bool on = !!(bm->optval & BIT(opt_id));
>> +
>> +err = br_boolopt_toggle(br, opt_id, on);
>> +if (err) {
>> +br_debug(br, "boolopt multi-toggle error: option: %d 
>> current: %d new: %d error: %d\n",
>> + opt_id, br_boolopt_get(br, opt_id), on, err);
>> +break;
>> +}
> 
> An old kernel with a new iproute2 might partially succeed in toggling
> some low bits, but then silently ignore a high bit that is not
> supported by the kernel. As a user, i want to know the kernel does not
> support an option i'm trying to toggle.
> 

That is already how netlink option setting works, if the option isn't supported
it is silently ignored. I tried to stay as close to the current behaviour as 
possible.
It also applies to partial option changes, some options will be changed until 
an error
is encountered.

> Can you walk all the bits in the u32 from the MSB to the LSB? That
> should avoid this problem.
> 

I did wonder about this and left it as netlink option behaviour but
I can leave the walk as is and just check if the highest order set bit >= 
BR_BOOLOPT_MAX
and err out with ENOTSUPP for example. Will reconsider for v2.

>   Andrew
> 



Re: [Bridge] [PATCH net-next 1/2] net: bridge: add support for user-controlled bool options

2018-11-22 Thread Nikolay Aleksandrov
On 22/11/2018 17:52, Andrew Lunn wrote:
>> +void br_boolopt_multi_get(const struct net_bridge *br,
>> +  struct br_boolopt_multi *bm)
>> +{
>> +u32 optval = 0;
>> +int opt_id;
>> +
>> +for (opt_id = 0; opt_id < BR_BOOLOPT_MAX; opt_id++)
>> +optval |= (br_boolopt_get(br, opt_id) << opt_id);
>> +
>> +bm->optval = optval;
>> +bm->optmask = 0;
> 
> Maybe set optmask to indicate which bits this kernel supports?
> 

I like the idea, will add for v2.

Thanks,
 Nik

>   Andrew
> 



Re: [Bridge] [PATCH net-next 1/2] net: bridge: add support for user-controlled bool options

2018-11-22 Thread Nikolay Aleksandrov
On 22/11/2018 17:35, Andrew Lunn wrote:
> On Thu, Nov 22, 2018 at 06:29:24AM +0200, Nikolay Aleksandrov wrote:
>> We have been adding many new bridge options, a big number of which are
>> boolean but still take up netlink attribute ids and waste space in the skb.
>> Recently we discussed learning from link-local packets[1] and decided
>> yet another new boolean option will be needed, thus introducing this API
>> to save some bridge nl space.
>> The API supports changing the value of multiple boolean options at once
>> via the br_boolopt_multi struct which has an optmask (which options to
>> set, bit per opt) and optval (options' new values). Future boolean
>> options will only be added to the br_boolopt_id enum and then will have
>> to be handled in br_boolopt_toggle/get. The API will automatically
>> add the ability to change and export them via netlink, sysfs can use the
>> single boolopt function versions to do the same. The behaviour with
>> failing/succeeding is the same as with normal netlink option changing.
>>
>> If an option requires mapping to internal kernel flag or needs special
>> configuration to be enabled then it should be handled in
>> br_boolopt_toggle. It should also be able to retrieve an option's current
>> state via br_boolopt_get.
>>
>> [1] https://www.spinics.net/lists/netdev/msg532698.html
>>
>> Signed-off-by: Nikolay Aleksandrov 
>> ---
>>  include/uapi/linux/if_bridge.h | 18 +
>>  include/uapi/linux/if_link.h   |  1 +
>>  net/bridge/br.c| 68 ++
>>  net/bridge/br_netlink.c| 17 -
>>  net/bridge/br_private.h|  6 +++
>>  net/core/rtnetlink.c   |  2 +-
>>  6 files changed, 110 insertions(+), 2 deletions(-)
>>
>> diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
>> index e41eda3c71f1..6dc02c03bdf8 100644
>> --- a/include/uapi/linux/if_bridge.h
>> +++ b/include/uapi/linux/if_bridge.h
>> @@ -292,4 +292,22 @@ struct br_mcast_stats {
>>  __u64 mcast_bytes[BR_MCAST_DIR_SIZE];
>>  __u64 mcast_packets[BR_MCAST_DIR_SIZE];
>>  };
>> +
>> +/* bridge boolean options
>> + * IMPORTANT: if adding a new option do not forget to handle
>> + *it in br_boolopt_toggle/get and bridge sysfs
>> + */
>> +enum br_boolopt_id {
>> +BR_BOOLOPT_MAX
>> +};
>> +
>> +/* struct br_boolopt_multi - change multiple bridge boolean options
>> + *
>> + * @optval: new option values (bit per option)
>> + * @optmask: options to change (bit per option)
>> + */
>> +struct br_boolopt_multi {
>> +__u32 optval;
>> +__u32 optmask;
>> +};
> 
> Hi Nikolay
> 
> Thanks for handling this.
> 
> How many boolean options do we already have? What it the likelihood a
> u32 is going to be too small, in a couple of years time?
> 

It would mean doubling the number of current options and this is only for
boolean options so I think we're safe.

> I recently went through the pain of converting the u32 for
> representing link modes in the phylib API to a linux bitmap.  I'm just
> wondering if in the long run, using a linux bitmap right from the
> beginning would be better?
> 
>> +int br_boolopt_multi_toggle(struct net_bridge *br,
>> +struct br_boolopt_multi *bm)
>> +{
>> +unsigned long bitmap = bm->optmask;
>> +int err = 0;
>> +int opt_id;
>> +
>> +for_each_set_bit(opt_id, , BR_BOOLOPT_MAX) {
>> +bool on = !!(bm->optval & BIT(opt_id));
>> +
>> +err = br_boolopt_toggle(br, opt_id, on);
>> +if (err) {
>> +br_debug(br, "boolopt multi-toggle error: option: %d 
>> current: %d new: %d error: %d\n",
>> + opt_id, br_boolopt_get(br, opt_id), on, err);
> 
> Would it be possible to return that to userspace using the extended
> error infrastructure?
> 

No, it doesn't support dynamic messages AFAIK.

>   Andrew
> 



Re: [Bridge] [PATCH net-next 1/2] net: bridge: add support for user-controlled bool options

2018-11-22 Thread Andrew Lunn
> +void br_boolopt_multi_get(const struct net_bridge *br,
> +   struct br_boolopt_multi *bm)
> +{
> + u32 optval = 0;
> + int opt_id;
> +
> + for (opt_id = 0; opt_id < BR_BOOLOPT_MAX; opt_id++)
> + optval |= (br_boolopt_get(br, opt_id) << opt_id);
> +
> + bm->optval = optval;
> + bm->optmask = 0;

Maybe set optmask to indicate which bits this kernel supports?

  Andrew


Re: [Bridge] [PATCH net-next 1/2] net: bridge: add support for user-controlled bool options

2018-11-22 Thread Andrew Lunn
> +/* br_boolopt_toggle - change user-controlled boolean option
> + *
> + * @br: bridge device
> + * @opt: id of the option to change
> + * @on: new option value
> + *
> + * Changes the value of the respective boolean option to @on taking care of
> + * any internal option value mapping and configuration.
> + */
> +int br_boolopt_toggle(struct net_bridge *br, enum br_boolopt_id opt, bool on)
> +{
> + int err = -ENOENT;
> +
> + switch (opt) {
> + default:
> + break;
> + }
> +
> + return err;
> +}
> +


> +int br_boolopt_multi_toggle(struct net_bridge *br,
> + struct br_boolopt_multi *bm)
> +{
> + unsigned long bitmap = bm->optmask;
> + int err = 0;
> + int opt_id;
> +
> + for_each_set_bit(opt_id, , BR_BOOLOPT_MAX) {
> + bool on = !!(bm->optval & BIT(opt_id));
> +
> + err = br_boolopt_toggle(br, opt_id, on);
> + if (err) {
> + br_debug(br, "boolopt multi-toggle error: option: %d 
> current: %d new: %d error: %d\n",
> +  opt_id, br_boolopt_get(br, opt_id), on, err);
> + break;
> + }

An old kernel with a new iproute2 might partially succeed in toggling
some low bits, but then silently ignore a high bit that is not
supported by the kernel. As a user, i want to know the kernel does not
support an option i'm trying to toggle.

Can you walk all the bits in the u32 from the MSB to the LSB? That
should avoid this problem.

Andrew


Re: [Bridge] [PATCH net-next 1/2] net: bridge: add support for user-controlled bool options

2018-11-22 Thread Andrew Lunn
On Thu, Nov 22, 2018 at 06:29:24AM +0200, Nikolay Aleksandrov wrote:
> We have been adding many new bridge options, a big number of which are
> boolean but still take up netlink attribute ids and waste space in the skb.
> Recently we discussed learning from link-local packets[1] and decided
> yet another new boolean option will be needed, thus introducing this API
> to save some bridge nl space.
> The API supports changing the value of multiple boolean options at once
> via the br_boolopt_multi struct which has an optmask (which options to
> set, bit per opt) and optval (options' new values). Future boolean
> options will only be added to the br_boolopt_id enum and then will have
> to be handled in br_boolopt_toggle/get. The API will automatically
> add the ability to change and export them via netlink, sysfs can use the
> single boolopt function versions to do the same. The behaviour with
> failing/succeeding is the same as with normal netlink option changing.
> 
> If an option requires mapping to internal kernel flag or needs special
> configuration to be enabled then it should be handled in
> br_boolopt_toggle. It should also be able to retrieve an option's current
> state via br_boolopt_get.
> 
> [1] https://www.spinics.net/lists/netdev/msg532698.html
> 
> Signed-off-by: Nikolay Aleksandrov 
> ---
>  include/uapi/linux/if_bridge.h | 18 +
>  include/uapi/linux/if_link.h   |  1 +
>  net/bridge/br.c| 68 ++
>  net/bridge/br_netlink.c| 17 -
>  net/bridge/br_private.h|  6 +++
>  net/core/rtnetlink.c   |  2 +-
>  6 files changed, 110 insertions(+), 2 deletions(-)
> 
> diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
> index e41eda3c71f1..6dc02c03bdf8 100644
> --- a/include/uapi/linux/if_bridge.h
> +++ b/include/uapi/linux/if_bridge.h
> @@ -292,4 +292,22 @@ struct br_mcast_stats {
>   __u64 mcast_bytes[BR_MCAST_DIR_SIZE];
>   __u64 mcast_packets[BR_MCAST_DIR_SIZE];
>  };
> +
> +/* bridge boolean options
> + * IMPORTANT: if adding a new option do not forget to handle
> + *it in br_boolopt_toggle/get and bridge sysfs
> + */
> +enum br_boolopt_id {
> + BR_BOOLOPT_MAX
> +};
> +
> +/* struct br_boolopt_multi - change multiple bridge boolean options
> + *
> + * @optval: new option values (bit per option)
> + * @optmask: options to change (bit per option)
> + */
> +struct br_boolopt_multi {
> + __u32 optval;
> + __u32 optmask;
> +};

Hi Nikolay

Thanks for handling this.

How many boolean options do we already have? What it the likelihood a
u32 is going to be too small, in a couple of years time?

I recently went through the pain of converting the u32 for
representing link modes in the phylib API to a linux bitmap.  I'm just
wondering if in the long run, using a linux bitmap right from the
beginning would be better?

> +int br_boolopt_multi_toggle(struct net_bridge *br,
> + struct br_boolopt_multi *bm)
> +{
> + unsigned long bitmap = bm->optmask;
> + int err = 0;
> + int opt_id;
> +
> + for_each_set_bit(opt_id, , BR_BOOLOPT_MAX) {
> + bool on = !!(bm->optval & BIT(opt_id));
> +
> + err = br_boolopt_toggle(br, opt_id, on);
> + if (err) {
> + br_debug(br, "boolopt multi-toggle error: option: %d 
> current: %d new: %d error: %d\n",
> +  opt_id, br_boolopt_get(br, opt_id), on, err);

Would it be possible to return that to userspace using the extended
error infrastructure?

  Andrew


[Bridge] [PATCH net-next 1/2] net: bridge: add support for user-controlled bool options

2018-11-21 Thread Nikolay Aleksandrov
We have been adding many new bridge options, a big number of which are
boolean but still take up netlink attribute ids and waste space in the skb.
Recently we discussed learning from link-local packets[1] and decided
yet another new boolean option will be needed, thus introducing this API
to save some bridge nl space.
The API supports changing the value of multiple boolean options at once
via the br_boolopt_multi struct which has an optmask (which options to
set, bit per opt) and optval (options' new values). Future boolean
options will only be added to the br_boolopt_id enum and then will have
to be handled in br_boolopt_toggle/get. The API will automatically
add the ability to change and export them via netlink, sysfs can use the
single boolopt function versions to do the same. The behaviour with
failing/succeeding is the same as with normal netlink option changing.

If an option requires mapping to internal kernel flag or needs special
configuration to be enabled then it should be handled in
br_boolopt_toggle. It should also be able to retrieve an option's current
state via br_boolopt_get.

[1] https://www.spinics.net/lists/netdev/msg532698.html

Signed-off-by: Nikolay Aleksandrov 
---
 include/uapi/linux/if_bridge.h | 18 +
 include/uapi/linux/if_link.h   |  1 +
 net/bridge/br.c| 68 ++
 net/bridge/br_netlink.c| 17 -
 net/bridge/br_private.h|  6 +++
 net/core/rtnetlink.c   |  2 +-
 6 files changed, 110 insertions(+), 2 deletions(-)

diff --git a/include/uapi/linux/if_bridge.h b/include/uapi/linux/if_bridge.h
index e41eda3c71f1..6dc02c03bdf8 100644
--- a/include/uapi/linux/if_bridge.h
+++ b/include/uapi/linux/if_bridge.h
@@ -292,4 +292,22 @@ struct br_mcast_stats {
__u64 mcast_bytes[BR_MCAST_DIR_SIZE];
__u64 mcast_packets[BR_MCAST_DIR_SIZE];
 };
+
+/* bridge boolean options
+ * IMPORTANT: if adding a new option do not forget to handle
+ *it in br_boolopt_toggle/get and bridge sysfs
+ */
+enum br_boolopt_id {
+   BR_BOOLOPT_MAX
+};
+
+/* struct br_boolopt_multi - change multiple bridge boolean options
+ *
+ * @optval: new option values (bit per option)
+ * @optmask: options to change (bit per option)
+ */
+struct br_boolopt_multi {
+   __u32 optval;
+   __u32 optmask;
+};
 #endif /* _UAPI_LINUX_IF_BRIDGE_H */
diff --git a/include/uapi/linux/if_link.h b/include/uapi/linux/if_link.h
index f42c069d81db..d6533828123a 100644
--- a/include/uapi/linux/if_link.h
+++ b/include/uapi/linux/if_link.h
@@ -288,6 +288,7 @@ enum {
IFLA_BR_MCAST_IGMP_VERSION,
IFLA_BR_MCAST_MLD_VERSION,
IFLA_BR_VLAN_STATS_PER_PORT,
+   IFLA_BR_MULTI_BOOLOPT,
__IFLA_BR_MAX,
 };
 
diff --git a/net/bridge/br.c b/net/bridge/br.c
index 360ad66c21e9..290b0adbf6d6 100644
--- a/net/bridge/br.c
+++ b/net/bridge/br.c
@@ -175,6 +175,74 @@ static struct notifier_block br_switchdev_notifier = {
.notifier_call = br_switchdev_event,
 };
 
+/* br_boolopt_toggle - change user-controlled boolean option
+ *
+ * @br: bridge device
+ * @opt: id of the option to change
+ * @on: new option value
+ *
+ * Changes the value of the respective boolean option to @on taking care of
+ * any internal option value mapping and configuration.
+ */
+int br_boolopt_toggle(struct net_bridge *br, enum br_boolopt_id opt, bool on)
+{
+   int err = -ENOENT;
+
+   switch (opt) {
+   default:
+   break;
+   }
+
+   return err;
+}
+
+int br_boolopt_get(const struct net_bridge *br, enum br_boolopt_id opt)
+{
+   int optval = 0;
+
+   switch (opt) {
+   default:
+   break;
+   }
+
+   return optval;
+}
+
+int br_boolopt_multi_toggle(struct net_bridge *br,
+   struct br_boolopt_multi *bm)
+{
+   unsigned long bitmap = bm->optmask;
+   int err = 0;
+   int opt_id;
+
+   for_each_set_bit(opt_id, , BR_BOOLOPT_MAX) {
+   bool on = !!(bm->optval & BIT(opt_id));
+
+   err = br_boolopt_toggle(br, opt_id, on);
+   if (err) {
+   br_debug(br, "boolopt multi-toggle error: option: %d 
current: %d new: %d error: %d\n",
+opt_id, br_boolopt_get(br, opt_id), on, err);
+   break;
+   }
+   }
+
+   return err;
+}
+
+void br_boolopt_multi_get(const struct net_bridge *br,
+ struct br_boolopt_multi *bm)
+{
+   u32 optval = 0;
+   int opt_id;
+
+   for (opt_id = 0; opt_id < BR_BOOLOPT_MAX; opt_id++)
+   optval |= (br_boolopt_get(br, opt_id) << opt_id);
+
+   bm->optval = optval;
+   bm->optmask = 0;
+}
+
+/* private bridge options, controlled by the kernel */
 void br_opt_toggle(struct net_bridge *br, enum net_bridge_opts opt, bool on)
 {
bool cur = !!br_opt_get(br, opt);
diff --git a/net/bridge/br_netlink.c b/net/bridge/br_netlink.c
index