.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-or-later |
---|
1 | 2 | /* |
---|
2 | 3 | * Bridge netlink control interface |
---|
3 | 4 | * |
---|
4 | 5 | * Authors: |
---|
5 | 6 | * Stephen Hemminger <shemminger@osdl.org> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or |
---|
8 | | - * modify it under the terms of the GNU General Public License |
---|
9 | | - * as published by the Free Software Foundation; either version |
---|
10 | | - * 2 of the License, or (at your option) any later version. |
---|
11 | 7 | */ |
---|
12 | 8 | |
---|
13 | 9 | #include <linux/kernel.h> |
---|
.. | .. |
---|
102 | 98 | size_t vinfo_sz = 0; |
---|
103 | 99 | |
---|
104 | 100 | rcu_read_lock(); |
---|
105 | | - if (br_port_exists(dev)) { |
---|
106 | | - p = br_port_get_rcu(dev); |
---|
107 | | - vg = nbp_vlan_group_rcu(p); |
---|
| 101 | + if (netif_is_bridge_port(dev)) { |
---|
| 102 | + p = br_port_get_check_rcu(dev); |
---|
| 103 | + if (p) |
---|
| 104 | + vg = nbp_vlan_group_rcu(p); |
---|
108 | 105 | } else if (dev->priv_flags & IFF_EBRIDGE) { |
---|
109 | 106 | br = netdev_priv(dev); |
---|
110 | 107 | vg = br_vlan_group_rcu(br); |
---|
.. | .. |
---|
155 | 152 | + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MULTICAST_ROUTER */ |
---|
156 | 153 | #endif |
---|
157 | 154 | + nla_total_size(sizeof(u16)) /* IFLA_BRPORT_GROUP_FWD_MASK */ |
---|
| 155 | + + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MRP_RING_OPEN */ |
---|
| 156 | + + nla_total_size(sizeof(u8)) /* IFLA_BRPORT_MRP_IN_OPEN */ |
---|
158 | 157 | + 0; |
---|
159 | 158 | } |
---|
160 | 159 | |
---|
.. | .. |
---|
217 | 216 | nla_put_u16(skb, IFLA_BRPORT_GROUP_FWD_MASK, p->group_fwd_mask) || |
---|
218 | 217 | nla_put_u8(skb, IFLA_BRPORT_NEIGH_SUPPRESS, |
---|
219 | 218 | !!(p->flags & BR_NEIGH_SUPPRESS)) || |
---|
| 219 | + nla_put_u8(skb, IFLA_BRPORT_MRP_RING_OPEN, !!(p->flags & |
---|
| 220 | + BR_MRP_LOST_CONT)) || |
---|
| 221 | + nla_put_u8(skb, IFLA_BRPORT_MRP_IN_OPEN, |
---|
| 222 | + !!(p->flags & BR_MRP_LOST_IN_CONT)) || |
---|
220 | 223 | nla_put_u8(skb, IFLA_BRPORT_ISOLATED, !!(p->flags & BR_ISOLATED))) |
---|
221 | 224 | return -EMSGSIZE; |
---|
222 | 225 | |
---|
.. | .. |
---|
378 | 381 | u32 filter_mask, const struct net_device *dev) |
---|
379 | 382 | { |
---|
380 | 383 | u8 operstate = netif_running(dev) ? dev->operstate : IF_OPER_DOWN; |
---|
| 384 | + struct nlattr *af = NULL; |
---|
381 | 385 | struct net_bridge *br; |
---|
382 | 386 | struct ifinfomsg *hdr; |
---|
383 | 387 | struct nlmsghdr *nlh; |
---|
.. | .. |
---|
413 | 417 | goto nla_put_failure; |
---|
414 | 418 | |
---|
415 | 419 | if (event == RTM_NEWLINK && port) { |
---|
416 | | - struct nlattr *nest |
---|
417 | | - = nla_nest_start(skb, IFLA_PROTINFO | NLA_F_NESTED); |
---|
| 420 | + struct nlattr *nest; |
---|
418 | 421 | |
---|
| 422 | + nest = nla_nest_start(skb, IFLA_PROTINFO); |
---|
419 | 423 | if (nest == NULL || br_port_fill_attrs(skb, port) < 0) |
---|
420 | 424 | goto nla_put_failure; |
---|
421 | 425 | nla_nest_end(skb, nest); |
---|
| 426 | + } |
---|
| 427 | + |
---|
| 428 | + if (filter_mask & (RTEXT_FILTER_BRVLAN | |
---|
| 429 | + RTEXT_FILTER_BRVLAN_COMPRESSED | |
---|
| 430 | + RTEXT_FILTER_MRP)) { |
---|
| 431 | + af = nla_nest_start_noflag(skb, IFLA_AF_SPEC); |
---|
| 432 | + if (!af) |
---|
| 433 | + goto nla_put_failure; |
---|
422 | 434 | } |
---|
423 | 435 | |
---|
424 | 436 | /* Check if the VID information is requested */ |
---|
425 | 437 | if ((filter_mask & RTEXT_FILTER_BRVLAN) || |
---|
426 | 438 | (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) { |
---|
427 | 439 | struct net_bridge_vlan_group *vg; |
---|
428 | | - struct nlattr *af; |
---|
429 | 440 | int err; |
---|
430 | 441 | |
---|
431 | 442 | /* RCU needed because of the VLAN locking rules (rcu || rtnl) */ |
---|
.. | .. |
---|
439 | 450 | rcu_read_unlock(); |
---|
440 | 451 | goto done; |
---|
441 | 452 | } |
---|
442 | | - af = nla_nest_start(skb, IFLA_AF_SPEC); |
---|
443 | | - if (!af) { |
---|
444 | | - rcu_read_unlock(); |
---|
445 | | - goto nla_put_failure; |
---|
446 | | - } |
---|
447 | 453 | if (filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) |
---|
448 | 454 | err = br_fill_ifvlaninfo_compressed(skb, vg); |
---|
449 | 455 | else |
---|
.. | .. |
---|
454 | 460 | rcu_read_unlock(); |
---|
455 | 461 | if (err) |
---|
456 | 462 | goto nla_put_failure; |
---|
457 | | - nla_nest_end(skb, af); |
---|
| 463 | + } |
---|
| 464 | + |
---|
| 465 | + if (filter_mask & RTEXT_FILTER_MRP) { |
---|
| 466 | + int err; |
---|
| 467 | + |
---|
| 468 | + if (!br_mrp_enabled(br) || port) |
---|
| 469 | + goto done; |
---|
| 470 | + |
---|
| 471 | + rcu_read_lock(); |
---|
| 472 | + err = br_mrp_fill_info(skb, br); |
---|
| 473 | + rcu_read_unlock(); |
---|
| 474 | + |
---|
| 475 | + if (err) |
---|
| 476 | + goto nla_put_failure; |
---|
458 | 477 | } |
---|
459 | 478 | |
---|
460 | 479 | done: |
---|
| 480 | + if (af) |
---|
| 481 | + nla_nest_end(skb, af); |
---|
461 | 482 | nlmsg_end(skb, nlh); |
---|
462 | 483 | return 0; |
---|
463 | 484 | |
---|
.. | .. |
---|
517 | 538 | struct net_bridge_port *port = br_port_get_rtnl(dev); |
---|
518 | 539 | |
---|
519 | 540 | if (!port && !(filter_mask & RTEXT_FILTER_BRVLAN) && |
---|
520 | | - !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED)) |
---|
| 541 | + !(filter_mask & RTEXT_FILTER_BRVLAN_COMPRESSED) && |
---|
| 542 | + !(filter_mask & RTEXT_FILTER_MRP)) |
---|
521 | 543 | return 0; |
---|
522 | 544 | |
---|
523 | 545 | return br_fill_ifinfo(skb, port, pid, seq, RTM_NEWLINK, nlflags, |
---|
.. | .. |
---|
525 | 547 | } |
---|
526 | 548 | |
---|
527 | 549 | static int br_vlan_info(struct net_bridge *br, struct net_bridge_port *p, |
---|
528 | | - int cmd, struct bridge_vlan_info *vinfo, bool *changed) |
---|
| 550 | + int cmd, struct bridge_vlan_info *vinfo, bool *changed, |
---|
| 551 | + struct netlink_ext_ack *extack) |
---|
529 | 552 | { |
---|
530 | 553 | bool curr_change; |
---|
531 | 554 | int err = 0; |
---|
.. | .. |
---|
537 | 560 | * per-VLAN entry as well |
---|
538 | 561 | */ |
---|
539 | 562 | err = nbp_vlan_add(p, vinfo->vid, vinfo->flags, |
---|
540 | | - &curr_change); |
---|
| 563 | + &curr_change, extack); |
---|
541 | 564 | } else { |
---|
542 | 565 | vinfo->flags |= BRIDGE_VLAN_INFO_BRENTRY; |
---|
543 | 566 | err = br_vlan_add(br, vinfo->vid, vinfo->flags, |
---|
544 | | - &curr_change); |
---|
| 567 | + &curr_change, extack); |
---|
545 | 568 | } |
---|
546 | 569 | if (curr_change) |
---|
547 | 570 | *changed = true; |
---|
.. | .. |
---|
564 | 587 | return err; |
---|
565 | 588 | } |
---|
566 | 589 | |
---|
567 | | -static int br_process_vlan_info(struct net_bridge *br, |
---|
568 | | - struct net_bridge_port *p, int cmd, |
---|
569 | | - struct bridge_vlan_info *vinfo_curr, |
---|
570 | | - struct bridge_vlan_info **vinfo_last, |
---|
571 | | - bool *changed) |
---|
| 590 | +int br_process_vlan_info(struct net_bridge *br, |
---|
| 591 | + struct net_bridge_port *p, int cmd, |
---|
| 592 | + struct bridge_vlan_info *vinfo_curr, |
---|
| 593 | + struct bridge_vlan_info **vinfo_last, |
---|
| 594 | + bool *changed, |
---|
| 595 | + struct netlink_ext_ack *extack) |
---|
572 | 596 | { |
---|
573 | | - if (!vinfo_curr->vid || vinfo_curr->vid >= VLAN_VID_MASK) |
---|
| 597 | + int err, rtm_cmd; |
---|
| 598 | + |
---|
| 599 | + if (!br_vlan_valid_id(vinfo_curr->vid, extack)) |
---|
574 | 600 | return -EINVAL; |
---|
575 | 601 | |
---|
| 602 | + /* needed for vlan-only NEWVLAN/DELVLAN notifications */ |
---|
| 603 | + rtm_cmd = br_afspec_cmd_to_rtm(cmd); |
---|
| 604 | + |
---|
576 | 605 | if (vinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_BEGIN) { |
---|
577 | | - /* check if we are already processing a range */ |
---|
578 | | - if (*vinfo_last) |
---|
| 606 | + if (!br_vlan_valid_range(vinfo_curr, *vinfo_last, extack)) |
---|
579 | 607 | return -EINVAL; |
---|
580 | 608 | *vinfo_last = vinfo_curr; |
---|
581 | | - /* don't allow range of pvids */ |
---|
582 | | - if ((*vinfo_last)->flags & BRIDGE_VLAN_INFO_PVID) |
---|
583 | | - return -EINVAL; |
---|
584 | 609 | return 0; |
---|
585 | 610 | } |
---|
586 | 611 | |
---|
587 | 612 | if (*vinfo_last) { |
---|
588 | 613 | struct bridge_vlan_info tmp_vinfo; |
---|
589 | | - int v, err; |
---|
| 614 | + int v, v_change_start = 0; |
---|
590 | 615 | |
---|
591 | | - if (!(vinfo_curr->flags & BRIDGE_VLAN_INFO_RANGE_END)) |
---|
592 | | - return -EINVAL; |
---|
593 | | - |
---|
594 | | - if (vinfo_curr->vid <= (*vinfo_last)->vid) |
---|
| 616 | + if (!br_vlan_valid_range(vinfo_curr, *vinfo_last, extack)) |
---|
595 | 617 | return -EINVAL; |
---|
596 | 618 | |
---|
597 | 619 | memcpy(&tmp_vinfo, *vinfo_last, |
---|
598 | 620 | sizeof(struct bridge_vlan_info)); |
---|
599 | 621 | for (v = (*vinfo_last)->vid; v <= vinfo_curr->vid; v++) { |
---|
| 622 | + bool curr_change = false; |
---|
| 623 | + |
---|
600 | 624 | tmp_vinfo.vid = v; |
---|
601 | | - err = br_vlan_info(br, p, cmd, &tmp_vinfo, changed); |
---|
| 625 | + err = br_vlan_info(br, p, cmd, &tmp_vinfo, &curr_change, |
---|
| 626 | + extack); |
---|
602 | 627 | if (err) |
---|
603 | 628 | break; |
---|
| 629 | + if (curr_change) { |
---|
| 630 | + *changed = curr_change; |
---|
| 631 | + if (!v_change_start) |
---|
| 632 | + v_change_start = v; |
---|
| 633 | + } else { |
---|
| 634 | + /* nothing to notify yet */ |
---|
| 635 | + if (!v_change_start) |
---|
| 636 | + continue; |
---|
| 637 | + br_vlan_notify(br, p, v_change_start, |
---|
| 638 | + v - 1, rtm_cmd); |
---|
| 639 | + v_change_start = 0; |
---|
| 640 | + } |
---|
| 641 | + cond_resched(); |
---|
604 | 642 | } |
---|
| 643 | + /* v_change_start is set only if the last/whole range changed */ |
---|
| 644 | + if (v_change_start) |
---|
| 645 | + br_vlan_notify(br, p, v_change_start, |
---|
| 646 | + v - 1, rtm_cmd); |
---|
| 647 | + |
---|
605 | 648 | *vinfo_last = NULL; |
---|
606 | 649 | |
---|
607 | 650 | return err; |
---|
608 | 651 | } |
---|
609 | 652 | |
---|
610 | | - return br_vlan_info(br, p, cmd, vinfo_curr, changed); |
---|
| 653 | + err = br_vlan_info(br, p, cmd, vinfo_curr, changed, extack); |
---|
| 654 | + if (*changed) |
---|
| 655 | + br_vlan_notify(br, p, vinfo_curr->vid, 0, rtm_cmd); |
---|
| 656 | + |
---|
| 657 | + return err; |
---|
611 | 658 | } |
---|
612 | 659 | |
---|
613 | 660 | static int br_afspec(struct net_bridge *br, |
---|
614 | 661 | struct net_bridge_port *p, |
---|
615 | 662 | struct nlattr *af_spec, |
---|
616 | | - int cmd, bool *changed) |
---|
| 663 | + int cmd, bool *changed, |
---|
| 664 | + struct netlink_ext_ack *extack) |
---|
617 | 665 | { |
---|
618 | 666 | struct bridge_vlan_info *vinfo_curr = NULL; |
---|
619 | 667 | struct bridge_vlan_info *vinfo_last = NULL; |
---|
.. | .. |
---|
643 | 691 | return -EINVAL; |
---|
644 | 692 | vinfo_curr = nla_data(attr); |
---|
645 | 693 | err = br_process_vlan_info(br, p, cmd, vinfo_curr, |
---|
646 | | - &vinfo_last, changed); |
---|
| 694 | + &vinfo_last, changed, |
---|
| 695 | + extack); |
---|
| 696 | + if (err) |
---|
| 697 | + return err; |
---|
| 698 | + break; |
---|
| 699 | + case IFLA_BRIDGE_MRP: |
---|
| 700 | + err = br_mrp_parse(br, p, attr, cmd, extack); |
---|
647 | 701 | if (err) |
---|
648 | 702 | return err; |
---|
649 | 703 | break; |
---|
.. | .. |
---|
850 | 904 | } |
---|
851 | 905 | |
---|
852 | 906 | /* Change state and parameters on port. */ |
---|
853 | | -int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags) |
---|
| 907 | +int br_setlink(struct net_device *dev, struct nlmsghdr *nlh, u16 flags, |
---|
| 908 | + struct netlink_ext_ack *extack) |
---|
854 | 909 | { |
---|
855 | 910 | struct net_bridge *br = (struct net_bridge *)netdev_priv(dev); |
---|
856 | 911 | struct nlattr *tb[IFLA_BRPORT_MAX + 1]; |
---|
.. | .. |
---|
874 | 929 | |
---|
875 | 930 | if (p && protinfo) { |
---|
876 | 931 | if (protinfo->nla_type & NLA_F_NESTED) { |
---|
877 | | - err = nla_parse_nested(tb, IFLA_BRPORT_MAX, protinfo, |
---|
878 | | - br_port_policy, NULL); |
---|
| 932 | + err = nla_parse_nested_deprecated(tb, IFLA_BRPORT_MAX, |
---|
| 933 | + protinfo, |
---|
| 934 | + br_port_policy, |
---|
| 935 | + NULL); |
---|
879 | 936 | if (err) |
---|
880 | 937 | return err; |
---|
881 | 938 | |
---|
.. | .. |
---|
897 | 954 | } |
---|
898 | 955 | |
---|
899 | 956 | if (afspec) |
---|
900 | | - err = br_afspec(br, p, afspec, RTM_SETLINK, &changed); |
---|
| 957 | + err = br_afspec(br, p, afspec, RTM_SETLINK, &changed, extack); |
---|
901 | 958 | |
---|
902 | 959 | if (changed) |
---|
903 | 960 | br_ifinfo_notify(RTM_NEWLINK, br, p); |
---|
.. | .. |
---|
923 | 980 | if (!p && !(dev->priv_flags & IFF_EBRIDGE)) |
---|
924 | 981 | return -EINVAL; |
---|
925 | 982 | |
---|
926 | | - err = br_afspec(br, p, afspec, RTM_DELLINK, &changed); |
---|
| 983 | + err = br_afspec(br, p, afspec, RTM_DELLINK, &changed, NULL); |
---|
927 | 984 | if (changed) |
---|
928 | 985 | /* Send RTM_NEWLINK because userspace |
---|
929 | 986 | * expects RTM_NEWLINK for vlan dels |
---|
.. | .. |
---|
1034 | 1091 | [IFLA_BR_MCAST_STATS_ENABLED] = { .type = NLA_U8 }, |
---|
1035 | 1092 | [IFLA_BR_MCAST_IGMP_VERSION] = { .type = NLA_U8 }, |
---|
1036 | 1093 | [IFLA_BR_MCAST_MLD_VERSION] = { .type = NLA_U8 }, |
---|
| 1094 | + [IFLA_BR_VLAN_STATS_PER_PORT] = { .type = NLA_U8 }, |
---|
| 1095 | + [IFLA_BR_MULTI_BOOLOPT] = |
---|
| 1096 | + NLA_POLICY_EXACT_LEN(sizeof(struct br_boolopt_multi)), |
---|
1037 | 1097 | }; |
---|
1038 | 1098 | |
---|
1039 | 1099 | static int br_changelink(struct net_device *brdev, struct nlattr *tb[], |
---|
.. | .. |
---|
1073 | 1133 | if (data[IFLA_BR_STP_STATE]) { |
---|
1074 | 1134 | u32 stp_enabled = nla_get_u32(data[IFLA_BR_STP_STATE]); |
---|
1075 | 1135 | |
---|
1076 | | - br_stp_set_enabled(br, stp_enabled); |
---|
| 1136 | + err = br_stp_set_enabled(br, stp_enabled, extack); |
---|
| 1137 | + if (err) |
---|
| 1138 | + return err; |
---|
1077 | 1139 | } |
---|
1078 | 1140 | |
---|
1079 | 1141 | if (data[IFLA_BR_PRIORITY]) { |
---|
.. | .. |
---|
1102 | 1164 | if (data[IFLA_BR_VLAN_DEFAULT_PVID]) { |
---|
1103 | 1165 | __u16 defpvid = nla_get_u16(data[IFLA_BR_VLAN_DEFAULT_PVID]); |
---|
1104 | 1166 | |
---|
1105 | | - err = __br_vlan_set_default_pvid(br, defpvid); |
---|
| 1167 | + err = __br_vlan_set_default_pvid(br, defpvid, extack); |
---|
1106 | 1168 | if (err) |
---|
1107 | 1169 | return err; |
---|
1108 | 1170 | } |
---|
.. | .. |
---|
1111 | 1173 | __u8 vlan_stats = nla_get_u8(data[IFLA_BR_VLAN_STATS_ENABLED]); |
---|
1112 | 1174 | |
---|
1113 | 1175 | err = br_vlan_set_stats(br, vlan_stats); |
---|
| 1176 | + if (err) |
---|
| 1177 | + return err; |
---|
| 1178 | + } |
---|
| 1179 | + |
---|
| 1180 | + if (data[IFLA_BR_VLAN_STATS_PER_PORT]) { |
---|
| 1181 | + __u8 per_port = nla_get_u8(data[IFLA_BR_VLAN_STATS_PER_PORT]); |
---|
| 1182 | + |
---|
| 1183 | + err = br_vlan_set_stats_per_port(br, per_port); |
---|
1114 | 1184 | if (err) |
---|
1115 | 1185 | return err; |
---|
1116 | 1186 | } |
---|
.. | .. |
---|
1139 | 1209 | spin_lock_bh(&br->lock); |
---|
1140 | 1210 | memcpy(br->group_addr, new_addr, sizeof(br->group_addr)); |
---|
1141 | 1211 | spin_unlock_bh(&br->lock); |
---|
1142 | | - br->group_addr_set = true; |
---|
| 1212 | + br_opt_toggle(br, BROPT_GROUP_ADDR_SET, true); |
---|
1143 | 1213 | br_recalculate_fwd_mask(br); |
---|
1144 | 1214 | } |
---|
1145 | 1215 | |
---|
.. | .. |
---|
1158 | 1228 | if (data[IFLA_BR_MCAST_SNOOPING]) { |
---|
1159 | 1229 | u8 mcast_snooping = nla_get_u8(data[IFLA_BR_MCAST_SNOOPING]); |
---|
1160 | 1230 | |
---|
1161 | | - err = br_multicast_toggle(br, mcast_snooping); |
---|
1162 | | - if (err) |
---|
1163 | | - return err; |
---|
| 1231 | + br_multicast_toggle(br, mcast_snooping); |
---|
1164 | 1232 | } |
---|
1165 | 1233 | |
---|
1166 | 1234 | if (data[IFLA_BR_MCAST_QUERY_USE_IFADDR]) { |
---|
1167 | 1235 | u8 val; |
---|
1168 | 1236 | |
---|
1169 | 1237 | val = nla_get_u8(data[IFLA_BR_MCAST_QUERY_USE_IFADDR]); |
---|
1170 | | - br->multicast_query_use_ifaddr = !!val; |
---|
| 1238 | + br_opt_toggle(br, BROPT_MULTICAST_QUERY_USE_IFADDR, !!val); |
---|
1171 | 1239 | } |
---|
1172 | 1240 | |
---|
1173 | 1241 | if (data[IFLA_BR_MCAST_QUERIER]) { |
---|
.. | .. |
---|
1178 | 1246 | return err; |
---|
1179 | 1247 | } |
---|
1180 | 1248 | |
---|
1181 | | - if (data[IFLA_BR_MCAST_HASH_ELASTICITY]) { |
---|
1182 | | - u32 val = nla_get_u32(data[IFLA_BR_MCAST_HASH_ELASTICITY]); |
---|
| 1249 | + if (data[IFLA_BR_MCAST_HASH_ELASTICITY]) |
---|
| 1250 | + br_warn(br, "the hash_elasticity option has been deprecated and is always %u\n", |
---|
| 1251 | + RHT_ELASTICITY); |
---|
1183 | 1252 | |
---|
1184 | | - br->hash_elasticity = val; |
---|
1185 | | - } |
---|
1186 | | - |
---|
1187 | | - if (data[IFLA_BR_MCAST_HASH_MAX]) { |
---|
1188 | | - u32 hash_max = nla_get_u32(data[IFLA_BR_MCAST_HASH_MAX]); |
---|
1189 | | - |
---|
1190 | | - err = br_multicast_set_hash_max(br, hash_max); |
---|
1191 | | - if (err) |
---|
1192 | | - return err; |
---|
1193 | | - } |
---|
| 1253 | + if (data[IFLA_BR_MCAST_HASH_MAX]) |
---|
| 1254 | + br->hash_max = nla_get_u32(data[IFLA_BR_MCAST_HASH_MAX]); |
---|
1194 | 1255 | |
---|
1195 | 1256 | if (data[IFLA_BR_MCAST_LAST_MEMBER_CNT]) { |
---|
1196 | 1257 | u32 val = nla_get_u32(data[IFLA_BR_MCAST_LAST_MEMBER_CNT]); |
---|
.. | .. |
---|
1244 | 1305 | __u8 mcast_stats; |
---|
1245 | 1306 | |
---|
1246 | 1307 | mcast_stats = nla_get_u8(data[IFLA_BR_MCAST_STATS_ENABLED]); |
---|
1247 | | - br->multicast_stats_enabled = !!mcast_stats; |
---|
| 1308 | + br_opt_toggle(br, BROPT_MULTICAST_STATS_ENABLED, !!mcast_stats); |
---|
1248 | 1309 | } |
---|
1249 | 1310 | |
---|
1250 | 1311 | if (data[IFLA_BR_MCAST_IGMP_VERSION]) { |
---|
.. | .. |
---|
1271 | 1332 | if (data[IFLA_BR_NF_CALL_IPTABLES]) { |
---|
1272 | 1333 | u8 val = nla_get_u8(data[IFLA_BR_NF_CALL_IPTABLES]); |
---|
1273 | 1334 | |
---|
1274 | | - br->nf_call_iptables = val ? true : false; |
---|
| 1335 | + br_opt_toggle(br, BROPT_NF_CALL_IPTABLES, !!val); |
---|
1275 | 1336 | } |
---|
1276 | 1337 | |
---|
1277 | 1338 | if (data[IFLA_BR_NF_CALL_IP6TABLES]) { |
---|
1278 | 1339 | u8 val = nla_get_u8(data[IFLA_BR_NF_CALL_IP6TABLES]); |
---|
1279 | 1340 | |
---|
1280 | | - br->nf_call_ip6tables = val ? true : false; |
---|
| 1341 | + br_opt_toggle(br, BROPT_NF_CALL_IP6TABLES, !!val); |
---|
1281 | 1342 | } |
---|
1282 | 1343 | |
---|
1283 | 1344 | if (data[IFLA_BR_NF_CALL_ARPTABLES]) { |
---|
1284 | 1345 | u8 val = nla_get_u8(data[IFLA_BR_NF_CALL_ARPTABLES]); |
---|
1285 | 1346 | |
---|
1286 | | - br->nf_call_arptables = val ? true : false; |
---|
| 1347 | + br_opt_toggle(br, BROPT_NF_CALL_ARPTABLES, !!val); |
---|
1287 | 1348 | } |
---|
1288 | 1349 | #endif |
---|
| 1350 | + |
---|
| 1351 | + if (data[IFLA_BR_MULTI_BOOLOPT]) { |
---|
| 1352 | + struct br_boolopt_multi *bm; |
---|
| 1353 | + |
---|
| 1354 | + bm = nla_data(data[IFLA_BR_MULTI_BOOLOPT]); |
---|
| 1355 | + err = br_boolopt_multi_toggle(br, bm, extack); |
---|
| 1356 | + if (err) |
---|
| 1357 | + return err; |
---|
| 1358 | + } |
---|
1289 | 1359 | |
---|
1290 | 1360 | return 0; |
---|
1291 | 1361 | } |
---|
.. | .. |
---|
1327 | 1397 | nla_total_size(sizeof(__be16)) + /* IFLA_BR_VLAN_PROTOCOL */ |
---|
1328 | 1398 | nla_total_size(sizeof(u16)) + /* IFLA_BR_VLAN_DEFAULT_PVID */ |
---|
1329 | 1399 | nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_STATS_ENABLED */ |
---|
| 1400 | + nla_total_size(sizeof(u8)) + /* IFLA_BR_VLAN_STATS_PER_PORT */ |
---|
1330 | 1401 | #endif |
---|
1331 | 1402 | nla_total_size(sizeof(u16)) + /* IFLA_BR_GROUP_FWD_MASK */ |
---|
1332 | 1403 | nla_total_size(sizeof(struct ifla_bridge_id)) + /* IFLA_BR_ROOT_ID */ |
---|
.. | .. |
---|
1364 | 1435 | nla_total_size(sizeof(u8)) + /* IFLA_BR_NF_CALL_IP6TABLES */ |
---|
1365 | 1436 | nla_total_size(sizeof(u8)) + /* IFLA_BR_NF_CALL_ARPTABLES */ |
---|
1366 | 1437 | #endif |
---|
| 1438 | + nla_total_size(sizeof(struct br_boolopt_multi)) + /* IFLA_BR_MULTI_BOOLOPT */ |
---|
1367 | 1439 | 0; |
---|
1368 | 1440 | } |
---|
1369 | 1441 | |
---|
.. | .. |
---|
1377 | 1449 | u32 stp_enabled = br->stp_enabled; |
---|
1378 | 1450 | u16 priority = (br->bridge_id.prio[0] << 8) | br->bridge_id.prio[1]; |
---|
1379 | 1451 | u8 vlan_enabled = br_vlan_enabled(br->dev); |
---|
| 1452 | + struct br_boolopt_multi bm; |
---|
1380 | 1453 | u64 clockval; |
---|
1381 | 1454 | |
---|
1382 | 1455 | clockval = br_timer_value(&br->hello_timer); |
---|
.. | .. |
---|
1393 | 1466 | if (nla_put_u64_64bit(skb, IFLA_BR_GC_TIMER, clockval, IFLA_BR_PAD)) |
---|
1394 | 1467 | return -EMSGSIZE; |
---|
1395 | 1468 | |
---|
| 1469 | + br_boolopt_multi_get(br, &bm); |
---|
1396 | 1470 | if (nla_put_u32(skb, IFLA_BR_FORWARD_DELAY, forward_delay) || |
---|
1397 | 1471 | nla_put_u32(skb, IFLA_BR_HELLO_TIME, hello_time) || |
---|
1398 | 1472 | nla_put_u32(skb, IFLA_BR_MAX_AGE, age_time) || |
---|
.. | .. |
---|
1410 | 1484 | nla_put_u8(skb, IFLA_BR_TOPOLOGY_CHANGE, br->topology_change) || |
---|
1411 | 1485 | nla_put_u8(skb, IFLA_BR_TOPOLOGY_CHANGE_DETECTED, |
---|
1412 | 1486 | br->topology_change_detected) || |
---|
1413 | | - nla_put(skb, IFLA_BR_GROUP_ADDR, ETH_ALEN, br->group_addr)) |
---|
| 1487 | + nla_put(skb, IFLA_BR_GROUP_ADDR, ETH_ALEN, br->group_addr) || |
---|
| 1488 | + nla_put(skb, IFLA_BR_MULTI_BOOLOPT, sizeof(bm), &bm)) |
---|
1414 | 1489 | return -EMSGSIZE; |
---|
1415 | 1490 | |
---|
1416 | 1491 | #ifdef CONFIG_BRIDGE_VLAN_FILTERING |
---|
1417 | 1492 | if (nla_put_be16(skb, IFLA_BR_VLAN_PROTOCOL, br->vlan_proto) || |
---|
1418 | 1493 | nla_put_u16(skb, IFLA_BR_VLAN_DEFAULT_PVID, br->default_pvid) || |
---|
1419 | | - nla_put_u8(skb, IFLA_BR_VLAN_STATS_ENABLED, br->vlan_stats_enabled)) |
---|
| 1494 | + nla_put_u8(skb, IFLA_BR_VLAN_STATS_ENABLED, |
---|
| 1495 | + br_opt_get(br, BROPT_VLAN_STATS_ENABLED)) || |
---|
| 1496 | + nla_put_u8(skb, IFLA_BR_VLAN_STATS_PER_PORT, |
---|
| 1497 | + br_opt_get(br, BROPT_VLAN_STATS_PER_PORT))) |
---|
1420 | 1498 | return -EMSGSIZE; |
---|
1421 | 1499 | #endif |
---|
1422 | 1500 | #ifdef CONFIG_BRIDGE_IGMP_SNOOPING |
---|
1423 | 1501 | if (nla_put_u8(skb, IFLA_BR_MCAST_ROUTER, br->multicast_router) || |
---|
1424 | | - nla_put_u8(skb, IFLA_BR_MCAST_SNOOPING, !br->multicast_disabled) || |
---|
| 1502 | + nla_put_u8(skb, IFLA_BR_MCAST_SNOOPING, |
---|
| 1503 | + br_opt_get(br, BROPT_MULTICAST_ENABLED)) || |
---|
1425 | 1504 | nla_put_u8(skb, IFLA_BR_MCAST_QUERY_USE_IFADDR, |
---|
1426 | | - br->multicast_query_use_ifaddr) || |
---|
1427 | | - nla_put_u8(skb, IFLA_BR_MCAST_QUERIER, br->multicast_querier) || |
---|
| 1505 | + br_opt_get(br, BROPT_MULTICAST_QUERY_USE_IFADDR)) || |
---|
| 1506 | + nla_put_u8(skb, IFLA_BR_MCAST_QUERIER, |
---|
| 1507 | + br_opt_get(br, BROPT_MULTICAST_QUERIER)) || |
---|
1428 | 1508 | nla_put_u8(skb, IFLA_BR_MCAST_STATS_ENABLED, |
---|
1429 | | - br->multicast_stats_enabled) || |
---|
1430 | | - nla_put_u32(skb, IFLA_BR_MCAST_HASH_ELASTICITY, |
---|
1431 | | - br->hash_elasticity) || |
---|
| 1509 | + br_opt_get(br, BROPT_MULTICAST_STATS_ENABLED)) || |
---|
| 1510 | + nla_put_u32(skb, IFLA_BR_MCAST_HASH_ELASTICITY, RHT_ELASTICITY) || |
---|
1432 | 1511 | nla_put_u32(skb, IFLA_BR_MCAST_HASH_MAX, br->hash_max) || |
---|
1433 | 1512 | nla_put_u32(skb, IFLA_BR_MCAST_LAST_MEMBER_CNT, |
---|
1434 | 1513 | br->multicast_last_member_count) || |
---|
.. | .. |
---|
1469 | 1548 | #endif |
---|
1470 | 1549 | #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) |
---|
1471 | 1550 | if (nla_put_u8(skb, IFLA_BR_NF_CALL_IPTABLES, |
---|
1472 | | - br->nf_call_iptables ? 1 : 0) || |
---|
| 1551 | + br_opt_get(br, BROPT_NF_CALL_IPTABLES) ? 1 : 0) || |
---|
1473 | 1552 | nla_put_u8(skb, IFLA_BR_NF_CALL_IP6TABLES, |
---|
1474 | | - br->nf_call_ip6tables ? 1 : 0) || |
---|
| 1553 | + br_opt_get(br, BROPT_NF_CALL_IP6TABLES) ? 1 : 0) || |
---|
1475 | 1554 | nla_put_u8(skb, IFLA_BR_NF_CALL_ARPTABLES, |
---|
1476 | | - br->nf_call_arptables ? 1 : 0)) |
---|
| 1555 | + br_opt_get(br, BROPT_NF_CALL_ARPTABLES) ? 1 : 0)) |
---|
1477 | 1556 | return -EMSGSIZE; |
---|
1478 | 1557 | #endif |
---|
1479 | 1558 | |
---|
.. | .. |
---|
1512 | 1591 | |
---|
1513 | 1592 | return numvls * nla_total_size(sizeof(struct bridge_vlan_xstats)) + |
---|
1514 | 1593 | nla_total_size_64bit(sizeof(struct br_mcast_stats)) + |
---|
| 1594 | + (p ? nla_total_size_64bit(sizeof(p->stp_xstats)) : 0) + |
---|
1515 | 1595 | nla_total_size(0); |
---|
1516 | 1596 | } |
---|
1517 | 1597 | |
---|
.. | .. |
---|
1543 | 1623 | return -EINVAL; |
---|
1544 | 1624 | } |
---|
1545 | 1625 | |
---|
1546 | | - nest = nla_nest_start(skb, LINK_XSTATS_TYPE_BRIDGE); |
---|
| 1626 | + nest = nla_nest_start_noflag(skb, LINK_XSTATS_TYPE_BRIDGE); |
---|
1547 | 1627 | if (!nest) |
---|
1548 | 1628 | return -EMSGSIZE; |
---|
1549 | 1629 | |
---|
.. | .. |
---|
1583 | 1663 | br_multicast_get_stats(br, p, nla_data(nla)); |
---|
1584 | 1664 | } |
---|
1585 | 1665 | #endif |
---|
| 1666 | + |
---|
| 1667 | + if (p) { |
---|
| 1668 | + nla = nla_reserve_64bit(skb, BRIDGE_XSTATS_STP, |
---|
| 1669 | + sizeof(p->stp_xstats), |
---|
| 1670 | + BRIDGE_XSTATS_PAD); |
---|
| 1671 | + if (!nla) |
---|
| 1672 | + goto nla_put_failure; |
---|
| 1673 | + |
---|
| 1674 | + spin_lock_bh(&br->lock); |
---|
| 1675 | + memcpy(nla_data(nla), &p->stp_xstats, sizeof(p->stp_xstats)); |
---|
| 1676 | + spin_unlock_bh(&br->lock); |
---|
| 1677 | + } |
---|
| 1678 | + |
---|
1586 | 1679 | nla_nest_end(skb, nest); |
---|
1587 | 1680 | *prividx = 0; |
---|
1588 | 1681 | |
---|
.. | .. |
---|
1627 | 1720 | int err; |
---|
1628 | 1721 | |
---|
1629 | 1722 | br_mdb_init(); |
---|
| 1723 | + br_vlan_rtnl_init(); |
---|
1630 | 1724 | rtnl_af_register(&br_af_ops); |
---|
1631 | 1725 | |
---|
1632 | 1726 | err = rtnl_link_register(&br_link_ops); |
---|
.. | .. |
---|
1644 | 1738 | void br_netlink_fini(void) |
---|
1645 | 1739 | { |
---|
1646 | 1740 | br_mdb_uninit(); |
---|
| 1741 | + br_vlan_rtnl_uninit(); |
---|
1647 | 1742 | rtnl_af_unregister(&br_af_ops); |
---|
1648 | 1743 | rtnl_link_unregister(&br_link_ops); |
---|
1649 | 1744 | } |
---|