Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

net/smc: introduce list of pnetids for Ethernet devices

SMCD version 2 allows usage of ISM devices with hardware PNETID
only, if an Ethernet net_device exists with the same hardware PNETID.
This requires to maintain a list of pnetids belonging to
Ethernet net_devices, which is covered by this patch.

Signed-off-by: Ursula Braun <ubraun@linux.ibm.com>
Signed-off-by: Karsten Graul <kgraul@linux.ibm.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

authored by

Ursula Braun and committed by
David S. Miller
e888a2e8 8caaccf5

+153 -7
+1
net/smc/smc_netns.h
··· 16 16 /* per-network namespace private data */ 17 17 struct smc_net { 18 18 struct smc_pnettable pnettable; 19 + struct smc_pnetids_ndev pnetids_ndev; 19 20 }; 20 21 #endif
+138 -7
net/smc/smc_pnet.c
··· 29 29 #include "smc_ism.h" 30 30 #include "smc_core.h" 31 31 32 + static struct net_device *__pnet_find_base_ndev(struct net_device *ndev); 32 33 static struct net_device *pnet_find_base_ndev(struct net_device *ndev); 33 34 34 35 static const struct nla_policy smc_pnet_policy[SMC_PNETID_MAX + 1] = { ··· 713 712 .n_ops = ARRAY_SIZE(smc_pnet_ops) 714 713 }; 715 714 715 + bool smc_pnet_is_ndev_pnetid(struct net *net, u8 *pnetid) 716 + { 717 + struct smc_net *sn = net_generic(net, smc_net_id); 718 + struct smc_pnetids_ndev_entry *pe; 719 + bool rc = false; 720 + 721 + read_lock(&sn->pnetids_ndev.lock); 722 + list_for_each_entry(pe, &sn->pnetids_ndev.list, list) { 723 + if (smc_pnet_match(pnetid, pe->pnetid)) { 724 + rc = true; 725 + goto unlock; 726 + } 727 + } 728 + 729 + unlock: 730 + read_unlock(&sn->pnetids_ndev.lock); 731 + return rc; 732 + } 733 + 734 + static int smc_pnet_add_pnetid(struct net *net, u8 *pnetid) 735 + { 736 + struct smc_net *sn = net_generic(net, smc_net_id); 737 + struct smc_pnetids_ndev_entry *pe, *pi; 738 + 739 + pe = kzalloc(sizeof(*pe), GFP_KERNEL); 740 + if (!pe) 741 + return -ENOMEM; 742 + 743 + write_lock(&sn->pnetids_ndev.lock); 744 + list_for_each_entry(pi, &sn->pnetids_ndev.list, list) { 745 + if (smc_pnet_match(pnetid, pe->pnetid)) { 746 + refcount_inc(&pi->refcnt); 747 + kfree(pe); 748 + goto unlock; 749 + } 750 + } 751 + refcount_set(&pe->refcnt, 1); 752 + memcpy(pe->pnetid, pnetid, SMC_MAX_PNETID_LEN); 753 + list_add_tail(&pe->list, &sn->pnetids_ndev.list); 754 + 755 + unlock: 756 + write_unlock(&sn->pnetids_ndev.lock); 757 + return 0; 758 + } 759 + 760 + static void smc_pnet_remove_pnetid(struct net *net, u8 *pnetid) 761 + { 762 + struct smc_net *sn = net_generic(net, smc_net_id); 763 + struct smc_pnetids_ndev_entry *pe, *pe2; 764 + 765 + write_lock(&sn->pnetids_ndev.lock); 766 + list_for_each_entry_safe(pe, pe2, &sn->pnetids_ndev.list, list) { 767 + if (smc_pnet_match(pnetid, pe->pnetid)) { 768 + if (refcount_dec_and_test(&pe->refcnt)) { 769 + list_del(&pe->list); 770 + kfree(pe); 771 + } 772 + break; 773 + } 774 + } 775 + write_unlock(&sn->pnetids_ndev.lock); 776 + } 777 + 778 + static void smc_pnet_add_base_pnetid(struct net *net, struct net_device *dev, 779 + u8 *ndev_pnetid) 780 + { 781 + struct net_device *base_dev; 782 + 783 + base_dev = __pnet_find_base_ndev(dev); 784 + if (base_dev->flags & IFF_UP && 785 + !smc_pnetid_by_dev_port(base_dev->dev.parent, base_dev->dev_port, 786 + ndev_pnetid)) { 787 + /* add to PNETIDs list */ 788 + smc_pnet_add_pnetid(net, ndev_pnetid); 789 + } 790 + } 791 + 792 + /* create initial list of netdevice pnetids */ 793 + static void smc_pnet_create_pnetids_list(struct net *net) 794 + { 795 + u8 ndev_pnetid[SMC_MAX_PNETID_LEN]; 796 + struct net_device *dev; 797 + 798 + rtnl_lock(); 799 + for_each_netdev(net, dev) 800 + smc_pnet_add_base_pnetid(net, dev, ndev_pnetid); 801 + rtnl_unlock(); 802 + } 803 + 804 + /* clean up list of netdevice pnetids */ 805 + static void smc_pnet_destroy_pnetids_list(struct net *net) 806 + { 807 + struct smc_net *sn = net_generic(net, smc_net_id); 808 + struct smc_pnetids_ndev_entry *pe, *temp_pe; 809 + 810 + write_lock(&sn->pnetids_ndev.lock); 811 + list_for_each_entry_safe(pe, temp_pe, &sn->pnetids_ndev.list, list) { 812 + list_del(&pe->list); 813 + kfree(pe); 814 + } 815 + write_unlock(&sn->pnetids_ndev.lock); 816 + } 817 + 716 818 static int smc_pnet_netdev_event(struct notifier_block *this, 717 819 unsigned long event, void *ptr) 718 820 { 719 821 struct net_device *event_dev = netdev_notifier_info_to_dev(ptr); 822 + struct net *net = dev_net(event_dev); 823 + u8 ndev_pnetid[SMC_MAX_PNETID_LEN]; 720 824 721 825 switch (event) { 722 826 case NETDEV_REBOOT: ··· 830 724 return NOTIFY_OK; 831 725 case NETDEV_REGISTER: 832 726 smc_pnet_add_by_ndev(event_dev); 727 + return NOTIFY_OK; 728 + case NETDEV_UP: 729 + smc_pnet_add_base_pnetid(net, event_dev, ndev_pnetid); 730 + return NOTIFY_OK; 731 + case NETDEV_DOWN: 732 + event_dev = __pnet_find_base_ndev(event_dev); 733 + if (!smc_pnetid_by_dev_port(event_dev->dev.parent, 734 + event_dev->dev_port, ndev_pnetid)) { 735 + /* remove from PNETIDs list */ 736 + smc_pnet_remove_pnetid(net, ndev_pnetid); 737 + } 833 738 return NOTIFY_OK; 834 739 default: 835 740 return NOTIFY_DONE; ··· 856 739 { 857 740 struct smc_net *sn = net_generic(net, smc_net_id); 858 741 struct smc_pnettable *pnettable = &sn->pnettable; 742 + struct smc_pnetids_ndev *pnetids_ndev = &sn->pnetids_ndev; 859 743 860 744 INIT_LIST_HEAD(&pnettable->pnetlist); 861 745 rwlock_init(&pnettable->lock); 746 + INIT_LIST_HEAD(&pnetids_ndev->list); 747 + rwlock_init(&pnetids_ndev->lock); 748 + 749 + smc_pnet_create_pnetids_list(net); 862 750 863 751 return 0; 864 752 } ··· 878 756 rc = register_netdevice_notifier(&smc_netdev_notifier); 879 757 if (rc) 880 758 genl_unregister_family(&smc_pnet_nl_family); 759 + 881 760 return rc; 882 761 } 883 762 ··· 887 764 { 888 765 /* flush pnet table */ 889 766 smc_pnet_remove_by_pnetid(net, NULL); 767 + smc_pnet_destroy_pnetids_list(net); 890 768 } 891 769 892 770 void smc_pnet_exit(void) ··· 896 772 genl_unregister_family(&smc_pnet_nl_family); 897 773 } 898 774 899 - /* Determine one base device for stacked net devices. 900 - * If the lower device level contains more than one devices 901 - * (for instance with bonding slaves), just the first device 902 - * is used to reach a base device. 903 - */ 904 - static struct net_device *pnet_find_base_ndev(struct net_device *ndev) 775 + static struct net_device *__pnet_find_base_ndev(struct net_device *ndev) 905 776 { 906 777 int i, nest_lvl; 907 778 908 - rtnl_lock(); 779 + ASSERT_RTNL(); 909 780 nest_lvl = ndev->lower_level; 910 781 for (i = 0; i < nest_lvl; i++) { 911 782 struct list_head *lower = &ndev->adj_list.lower; ··· 910 791 lower = lower->next; 911 792 ndev = netdev_lower_get_next(ndev, &lower); 912 793 } 794 + return ndev; 795 + } 796 + 797 + /* Determine one base device for stacked net devices. 798 + * If the lower device level contains more than one devices 799 + * (for instance with bonding slaves), just the first device 800 + * is used to reach a base device. 801 + */ 802 + static struct net_device *pnet_find_base_ndev(struct net_device *ndev) 803 + { 804 + rtnl_lock(); 805 + ndev = __pnet_find_base_ndev(ndev); 913 806 rtnl_unlock(); 914 807 return ndev; 915 808 }
+14
net/smc/smc_pnet.h
··· 12 12 #ifndef _SMC_PNET_H 13 13 #define _SMC_PNET_H 14 14 15 + #include <net/smc.h> 16 + 15 17 #if IS_ENABLED(CONFIG_HAVE_PNETID) 16 18 #include <asm/pnet.h> 17 19 #endif ··· 31 29 struct smc_pnettable { 32 30 rwlock_t lock; 33 31 struct list_head pnetlist; 32 + }; 33 + 34 + struct smc_pnetids_ndev { /* list of pnetids for net devices in UP state*/ 35 + struct list_head list; 36 + rwlock_t lock; 37 + }; 38 + 39 + struct smc_pnetids_ndev_entry { 40 + struct list_head list; 41 + u8 pnetid[SMC_MAX_PNETID_LEN]; 42 + refcount_t refcnt; 34 43 }; 35 44 36 45 static inline int smc_pnetid_by_dev_port(struct device *dev, ··· 65 52 void smc_pnet_find_alt_roce(struct smc_link_group *lgr, 66 53 struct smc_init_info *ini, 67 54 struct smc_ib_device *known_dev); 55 + bool smc_pnet_is_ndev_pnetid(struct net *net, u8 *pnetid); 68 56 #endif