br_mdb.c (320424c7d44f54c18df9812fd7c45f6963524002) | br_mdb.c (9632233e7de8da43711bb7cd3e054af32fedcc38) |
---|---|
1// SPDX-License-Identifier: GPL-2.0 2#include <linux/err.h> 3#include <linux/igmp.h> 4#include <linux/kernel.h> 5#include <linux/netdevice.h> 6#include <linux/rculist.h> 7#include <linux/skbuff.h> 8#include <linux/if_ether.h> 9#include <net/ip.h> 10#include <net/netlink.h> 11#include <net/switchdev.h> 12#if IS_ENABLED(CONFIG_IPV6) 13#include <net/ipv6.h> 14#include <net/addrconf.h> 15#endif 16 17#include "br_private.h" 18 | 1// SPDX-License-Identifier: GPL-2.0 2#include <linux/err.h> 3#include <linux/igmp.h> 4#include <linux/kernel.h> 5#include <linux/netdevice.h> 6#include <linux/rculist.h> 7#include <linux/skbuff.h> 8#include <linux/if_ether.h> 9#include <net/ip.h> 10#include <net/netlink.h> 11#include <net/switchdev.h> 12#if IS_ENABLED(CONFIG_IPV6) 13#include <net/ipv6.h> 14#include <net/addrconf.h> 15#endif 16 17#include "br_private.h" 18 |
19static bool br_rports_have_mc_router(struct net_bridge *br) 20{ 21#if IS_ENABLED(CONFIG_IPV6) 22 return !hlist_empty(&br->ip4_mc_router_list) || 23 !hlist_empty(&br->ip6_mc_router_list); 24#else 25 return !hlist_empty(&br->ip4_mc_router_list); 26#endif 27} 28 29static bool 30br_ip4_rports_get_timer(struct net_bridge_port *port, unsigned long *timer) 31{ 32 *timer = br_timer_value(&port->multicast_ctx.ip4_mc_router_timer); 33 return !hlist_unhashed(&port->multicast_ctx.ip4_rlist); 34} 35 36static bool 37br_ip6_rports_get_timer(struct net_bridge_port *port, unsigned long *timer) 38{ 39#if IS_ENABLED(CONFIG_IPV6) 40 *timer = br_timer_value(&port->multicast_ctx.ip6_mc_router_timer); 41 return !hlist_unhashed(&port->multicast_ctx.ip6_rlist); 42#else 43 *timer = 0; 44 return false; 45#endif 46} 47 |
|
19static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb, 20 struct net_device *dev) 21{ 22 struct net_bridge *br = netdev_priv(dev); | 48static int br_rports_fill_info(struct sk_buff *skb, struct netlink_callback *cb, 49 struct net_device *dev) 50{ 51 struct net_bridge *br = netdev_priv(dev); |
23 struct net_bridge_port *p; | 52 bool have_ip4_mc_rtr, have_ip6_mc_rtr; 53 unsigned long ip4_timer, ip6_timer; |
24 struct nlattr *nest, *port_nest; | 54 struct nlattr *nest, *port_nest; |
55 struct net_bridge_port *p; |
|
25 | 56 |
26 if (!br->multicast_router || hlist_empty(&br->router_list)) | 57 if (!br->multicast_router) |
27 return 0; 28 | 58 return 0; 59 |
60 if (!br_rports_have_mc_router(br)) 61 return 0; 62 |
|
29 nest = nla_nest_start_noflag(skb, MDBA_ROUTER); 30 if (nest == NULL) 31 return -EMSGSIZE; 32 | 63 nest = nla_nest_start_noflag(skb, MDBA_ROUTER); 64 if (nest == NULL) 65 return -EMSGSIZE; 66 |
33 hlist_for_each_entry_rcu(p, &br->router_list, rlist) { 34 if (!p) | 67 list_for_each_entry_rcu(p, &br->port_list, list) { 68 have_ip4_mc_rtr = br_ip4_rports_get_timer(p, &ip4_timer); 69 have_ip6_mc_rtr = br_ip6_rports_get_timer(p, &ip6_timer); 70 71 if (!have_ip4_mc_rtr && !have_ip6_mc_rtr) |
35 continue; | 72 continue; |
73 |
|
36 port_nest = nla_nest_start_noflag(skb, MDBA_ROUTER_PORT); 37 if (!port_nest) 38 goto fail; | 74 port_nest = nla_nest_start_noflag(skb, MDBA_ROUTER_PORT); 75 if (!port_nest) 76 goto fail; |
77 |
|
39 if (nla_put_nohdr(skb, sizeof(u32), &p->dev->ifindex) || 40 nla_put_u32(skb, MDBA_ROUTER_PATTR_TIMER, | 78 if (nla_put_nohdr(skb, sizeof(u32), &p->dev->ifindex) || 79 nla_put_u32(skb, MDBA_ROUTER_PATTR_TIMER, |
41 br_timer_value(&p->multicast_router_timer)) || | 80 max(ip4_timer, ip6_timer)) || |
42 nla_put_u8(skb, MDBA_ROUTER_PATTR_TYPE, | 81 nla_put_u8(skb, MDBA_ROUTER_PATTR_TYPE, |
43 p->multicast_router)) { | 82 p->multicast_ctx.multicast_router) || 83 (have_ip4_mc_rtr && 84 nla_put_u32(skb, MDBA_ROUTER_PATTR_INET_TIMER, 85 ip4_timer)) || 86 (have_ip6_mc_rtr && 87 nla_put_u32(skb, MDBA_ROUTER_PATTR_INET6_TIMER, 88 ip6_timer))) { |
44 nla_nest_cancel(skb, port_nest); 45 goto fail; 46 } 47 nla_nest_end(skb, port_nest); 48 } 49 50 nla_nest_end(skb, nest); 51 return 0; --- 465 unchanged lines hidden (view full) --- 517#endif 518 else 519 ether_addr_copy(mdb->addr, mp->addr.dst.mac_addr); 520 521 mdb->vid = mp->addr.vid; 522} 523 524static int br_mdb_replay_one(struct notifier_block *nb, struct net_device *dev, | 89 nla_nest_cancel(skb, port_nest); 90 goto fail; 91 } 92 nla_nest_end(skb, port_nest); 93 } 94 95 nla_nest_end(skb, nest); 96 return 0; --- 465 unchanged lines hidden (view full) --- 562#endif 563 else 564 ether_addr_copy(mdb->addr, mp->addr.dst.mac_addr); 565 566 mdb->vid = mp->addr.vid; 567} 568 569static int br_mdb_replay_one(struct notifier_block *nb, struct net_device *dev, |
525 struct switchdev_obj_port_mdb *mdb, | 570 const struct switchdev_obj_port_mdb *mdb, 571 unsigned long action, const void *ctx, |
526 struct netlink_ext_ack *extack) 527{ 528 struct switchdev_notifier_port_obj_info obj_info = { 529 .info = { 530 .dev = dev, 531 .extack = extack, | 572 struct netlink_ext_ack *extack) 573{ 574 struct switchdev_notifier_port_obj_info obj_info = { 575 .info = { 576 .dev = dev, 577 .extack = extack, |
578 .ctx = ctx, |
|
532 }, 533 .obj = &mdb->obj, 534 }; 535 int err; 536 | 579 }, 580 .obj = &mdb->obj, 581 }; 582 int err; 583 |
537 err = nb->notifier_call(nb, SWITCHDEV_PORT_OBJ_ADD, &obj_info); | 584 err = nb->notifier_call(nb, action, &obj_info); |
538 return notifier_to_errno(err); 539} 540 541static int br_mdb_queue_one(struct list_head *mdb_list, 542 enum switchdev_obj_id id, 543 const struct net_bridge_mdb_entry *mp, 544 struct net_device *orig_dev) 545{ --- 7 unchanged lines hidden (view full) --- 553 mdb->obj.orig_dev = orig_dev; 554 br_switchdev_mdb_populate(mdb, mp); 555 list_add_tail(&mdb->obj.list, mdb_list); 556 557 return 0; 558} 559 560int br_mdb_replay(struct net_device *br_dev, struct net_device *dev, | 585 return notifier_to_errno(err); 586} 587 588static int br_mdb_queue_one(struct list_head *mdb_list, 589 enum switchdev_obj_id id, 590 const struct net_bridge_mdb_entry *mp, 591 struct net_device *orig_dev) 592{ --- 7 unchanged lines hidden (view full) --- 600 mdb->obj.orig_dev = orig_dev; 601 br_switchdev_mdb_populate(mdb, mp); 602 list_add_tail(&mdb->obj.list, mdb_list); 603 604 return 0; 605} 606 607int br_mdb_replay(struct net_device *br_dev, struct net_device *dev, |
561 struct notifier_block *nb, struct netlink_ext_ack *extack) | 608 const void *ctx, bool adding, struct notifier_block *nb, 609 struct netlink_ext_ack *extack) |
562{ | 610{ |
563 struct net_bridge_mdb_entry *mp; | 611 const struct net_bridge_mdb_entry *mp; |
564 struct switchdev_obj *obj, *tmp; 565 struct net_bridge *br; | 612 struct switchdev_obj *obj, *tmp; 613 struct net_bridge *br; |
614 unsigned long action; |
|
566 LIST_HEAD(mdb_list); 567 int err = 0; 568 569 ASSERT_RTNL(); 570 571 if (!netif_is_bridge_master(br_dev) || !netif_is_bridge_port(dev)) 572 return -EINVAL; 573 --- 8 unchanged lines hidden (view full) --- 582 * switchdev event, so since both br->multicast_lock and RCU read side 583 * critical sections are atomic, we have no choice but to pick the RCU 584 * read side lock, queue up all our events, leave the critical section 585 * and notify switchdev from blocking context. 586 */ 587 rcu_read_lock(); 588 589 hlist_for_each_entry_rcu(mp, &br->mdb_list, mdb_node) { | 615 LIST_HEAD(mdb_list); 616 int err = 0; 617 618 ASSERT_RTNL(); 619 620 if (!netif_is_bridge_master(br_dev) || !netif_is_bridge_port(dev)) 621 return -EINVAL; 622 --- 8 unchanged lines hidden (view full) --- 631 * switchdev event, so since both br->multicast_lock and RCU read side 632 * critical sections are atomic, we have no choice but to pick the RCU 633 * read side lock, queue up all our events, leave the critical section 634 * and notify switchdev from blocking context. 635 */ 636 rcu_read_lock(); 637 638 hlist_for_each_entry_rcu(mp, &br->mdb_list, mdb_node) { |
590 struct net_bridge_port_group __rcu **pp; 591 struct net_bridge_port_group *p; | 639 struct net_bridge_port_group __rcu * const *pp; 640 const struct net_bridge_port_group *p; |
592 593 if (mp->host_joined) { 594 err = br_mdb_queue_one(&mdb_list, 595 SWITCHDEV_OBJ_ID_HOST_MDB, 596 mp, br_dev); 597 if (err) { 598 rcu_read_unlock(); 599 goto out_free_mdb; --- 12 unchanged lines hidden (view full) --- 612 rcu_read_unlock(); 613 goto out_free_mdb; 614 } 615 } 616 } 617 618 rcu_read_unlock(); 619 | 641 642 if (mp->host_joined) { 643 err = br_mdb_queue_one(&mdb_list, 644 SWITCHDEV_OBJ_ID_HOST_MDB, 645 mp, br_dev); 646 if (err) { 647 rcu_read_unlock(); 648 goto out_free_mdb; --- 12 unchanged lines hidden (view full) --- 661 rcu_read_unlock(); 662 goto out_free_mdb; 663 } 664 } 665 } 666 667 rcu_read_unlock(); 668 |
669 if (adding) 670 action = SWITCHDEV_PORT_OBJ_ADD; 671 else 672 action = SWITCHDEV_PORT_OBJ_DEL; 673 |
|
620 list_for_each_entry(obj, &mdb_list, list) { 621 err = br_mdb_replay_one(nb, dev, SWITCHDEV_OBJ_PORT_MDB(obj), | 674 list_for_each_entry(obj, &mdb_list, list) { 675 err = br_mdb_replay_one(nb, dev, SWITCHDEV_OBJ_PORT_MDB(obj), |
622 extack); | 676 action, ctx, extack); |
623 if (err) 624 goto out_free_mdb; 625 } 626 627out_free_mdb: 628 list_for_each_entry_safe(obj, tmp, &mdb_list, list) { 629 list_del(&obj->list); 630 kfree(SWITCHDEV_OBJ_PORT_MDB(obj)); --- 622 unchanged lines hidden --- | 677 if (err) 678 goto out_free_mdb; 679 } 680 681out_free_mdb: 682 list_for_each_entry_safe(obj, tmp, &mdb_list, list) { 683 list_del(&obj->list); 684 kfree(SWITCHDEV_OBJ_PORT_MDB(obj)); --- 622 unchanged lines hidden --- |