diff options
Diffstat (limited to 'net')
-rw-r--r-- | net/bridge/br_fdb.c | 23 | ||||
-rw-r--r-- | net/bridge/br_private.h | 2 | ||||
-rw-r--r-- | net/core/rtnetlink.c | 105 | ||||
-rw-r--r-- | net/switchdev/switchdev.c | 10 |
4 files changed, 83 insertions, 57 deletions
diff --git a/net/bridge/br_fdb.c b/net/bridge/br_fdb.c index cd620fab41b0..6b43c8c88f19 100644 --- a/net/bridge/br_fdb.c +++ b/net/bridge/br_fdb.c | |||
@@ -710,24 +710,27 @@ int br_fdb_dump(struct sk_buff *skb, | |||
710 | struct netlink_callback *cb, | 710 | struct netlink_callback *cb, |
711 | struct net_device *dev, | 711 | struct net_device *dev, |
712 | struct net_device *filter_dev, | 712 | struct net_device *filter_dev, |
713 | int idx) | 713 | int *idx) |
714 | { | 714 | { |
715 | struct net_bridge *br = netdev_priv(dev); | 715 | struct net_bridge *br = netdev_priv(dev); |
716 | int err = 0; | ||
716 | int i; | 717 | int i; |
717 | 718 | ||
718 | if (!(dev->priv_flags & IFF_EBRIDGE)) | 719 | if (!(dev->priv_flags & IFF_EBRIDGE)) |
719 | goto out; | 720 | goto out; |
720 | 721 | ||
721 | if (!filter_dev) | 722 | if (!filter_dev) { |
722 | idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx); | 723 | err = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx); |
724 | if (err < 0) | ||
725 | goto out; | ||
726 | } | ||
723 | 727 | ||
724 | for (i = 0; i < BR_HASH_SIZE; i++) { | 728 | for (i = 0; i < BR_HASH_SIZE; i++) { |
725 | struct net_bridge_fdb_entry *f; | 729 | struct net_bridge_fdb_entry *f; |
726 | 730 | ||
727 | hlist_for_each_entry_rcu(f, &br->hash[i], hlist) { | 731 | hlist_for_each_entry_rcu(f, &br->hash[i], hlist) { |
728 | int err; | ||
729 | 732 | ||
730 | if (idx < cb->args[0]) | 733 | if (*idx < cb->args[2]) |
731 | goto skip; | 734 | goto skip; |
732 | 735 | ||
733 | if (filter_dev && | 736 | if (filter_dev && |
@@ -750,17 +753,15 @@ int br_fdb_dump(struct sk_buff *skb, | |||
750 | cb->nlh->nlmsg_seq, | 753 | cb->nlh->nlmsg_seq, |
751 | RTM_NEWNEIGH, | 754 | RTM_NEWNEIGH, |
752 | NLM_F_MULTI); | 755 | NLM_F_MULTI); |
753 | if (err < 0) { | 756 | if (err < 0) |
754 | cb->args[1] = err; | 757 | goto out; |
755 | break; | ||
756 | } | ||
757 | skip: | 758 | skip: |
758 | ++idx; | 759 | *idx += 1; |
759 | } | 760 | } |
760 | } | 761 | } |
761 | 762 | ||
762 | out: | 763 | out: |
763 | return idx; | 764 | return err; |
764 | } | 765 | } |
765 | 766 | ||
766 | /* Update (create or replace) forwarding database entry */ | 767 | /* Update (create or replace) forwarding database entry */ |
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h index 2379b2b865c9..3d36493f4487 100644 --- a/net/bridge/br_private.h +++ b/net/bridge/br_private.h | |||
@@ -508,7 +508,7 @@ int br_fdb_delete(struct ndmsg *ndm, struct nlattr *tb[], | |||
508 | int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev, | 508 | int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev, |
509 | const unsigned char *addr, u16 vid, u16 nlh_flags); | 509 | const unsigned char *addr, u16 vid, u16 nlh_flags); |
510 | int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, | 510 | int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, |
511 | struct net_device *dev, struct net_device *fdev, int idx); | 511 | struct net_device *dev, struct net_device *fdev, int *idx); |
512 | int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p); | 512 | int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p); |
513 | void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p); | 513 | void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p); |
514 | int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, | 514 | int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, |
diff --git a/net/core/rtnetlink.c b/net/core/rtnetlink.c index 318fc5231b2b..1dfca1c3f8f5 100644 --- a/net/core/rtnetlink.c +++ b/net/core/rtnetlink.c | |||
@@ -3068,7 +3068,7 @@ static int nlmsg_populate_fdb(struct sk_buff *skb, | |||
3068 | seq = cb->nlh->nlmsg_seq; | 3068 | seq = cb->nlh->nlmsg_seq; |
3069 | 3069 | ||
3070 | list_for_each_entry(ha, &list->list, list) { | 3070 | list_for_each_entry(ha, &list->list, list) { |
3071 | if (*idx < cb->args[0]) | 3071 | if (*idx < cb->args[2]) |
3072 | goto skip; | 3072 | goto skip; |
3073 | 3073 | ||
3074 | err = nlmsg_populate_fdb_fill(skb, dev, ha->addr, 0, | 3074 | err = nlmsg_populate_fdb_fill(skb, dev, ha->addr, 0, |
@@ -3095,19 +3095,18 @@ int ndo_dflt_fdb_dump(struct sk_buff *skb, | |||
3095 | struct netlink_callback *cb, | 3095 | struct netlink_callback *cb, |
3096 | struct net_device *dev, | 3096 | struct net_device *dev, |
3097 | struct net_device *filter_dev, | 3097 | struct net_device *filter_dev, |
3098 | int idx) | 3098 | int *idx) |
3099 | { | 3099 | { |
3100 | int err; | 3100 | int err; |
3101 | 3101 | ||
3102 | netif_addr_lock_bh(dev); | 3102 | netif_addr_lock_bh(dev); |
3103 | err = nlmsg_populate_fdb(skb, cb, dev, &idx, &dev->uc); | 3103 | err = nlmsg_populate_fdb(skb, cb, dev, idx, &dev->uc); |
3104 | if (err) | 3104 | if (err) |
3105 | goto out; | 3105 | goto out; |
3106 | nlmsg_populate_fdb(skb, cb, dev, &idx, &dev->mc); | 3106 | nlmsg_populate_fdb(skb, cb, dev, idx, &dev->mc); |
3107 | out: | 3107 | out: |
3108 | netif_addr_unlock_bh(dev); | 3108 | netif_addr_unlock_bh(dev); |
3109 | cb->args[1] = err; | 3109 | return err; |
3110 | return idx; | ||
3111 | } | 3110 | } |
3112 | EXPORT_SYMBOL(ndo_dflt_fdb_dump); | 3111 | EXPORT_SYMBOL(ndo_dflt_fdb_dump); |
3113 | 3112 | ||
@@ -3120,9 +3119,13 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
3120 | const struct net_device_ops *cops = NULL; | 3119 | const struct net_device_ops *cops = NULL; |
3121 | struct ifinfomsg *ifm = nlmsg_data(cb->nlh); | 3120 | struct ifinfomsg *ifm = nlmsg_data(cb->nlh); |
3122 | struct net *net = sock_net(skb->sk); | 3121 | struct net *net = sock_net(skb->sk); |
3122 | struct hlist_head *head; | ||
3123 | int brport_idx = 0; | 3123 | int brport_idx = 0; |
3124 | int br_idx = 0; | 3124 | int br_idx = 0; |
3125 | int idx = 0; | 3125 | int h, s_h; |
3126 | int idx = 0, s_idx; | ||
3127 | int err = 0; | ||
3128 | int fidx = 0; | ||
3126 | 3129 | ||
3127 | if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, | 3130 | if (nlmsg_parse(cb->nlh, sizeof(struct ifinfomsg), tb, IFLA_MAX, |
3128 | ifla_policy) == 0) { | 3131 | ifla_policy) == 0) { |
@@ -3140,49 +3143,71 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb) | |||
3140 | ops = br_dev->netdev_ops; | 3143 | ops = br_dev->netdev_ops; |
3141 | } | 3144 | } |
3142 | 3145 | ||
3143 | cb->args[1] = 0; | 3146 | s_h = cb->args[0]; |
3144 | for_each_netdev(net, dev) { | 3147 | s_idx = cb->args[1]; |
3145 | if (brport_idx && (dev->ifindex != brport_idx)) | ||
3146 | continue; | ||
3147 | 3148 | ||
3148 | if (!br_idx) { /* user did not specify a specific bridge */ | 3149 | for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) { |
3149 | if (dev->priv_flags & IFF_BRIDGE_PORT) { | 3150 | idx = 0; |
3150 | br_dev = netdev_master_upper_dev_get(dev); | 3151 | head = &net->dev_index_head[h]; |
3151 | cops = br_dev->netdev_ops; | 3152 | hlist_for_each_entry(dev, head, index_hlist) { |
3152 | } | ||
3153 | 3153 | ||
3154 | } else { | 3154 | if (brport_idx && (dev->ifindex != brport_idx)) |
3155 | if (dev != br_dev && | ||
3156 | !(dev->priv_flags & IFF_BRIDGE_PORT)) | ||
3157 | continue; | 3155 | continue; |
3158 | 3156 | ||
3159 | if (br_dev != netdev_master_upper_dev_get(dev) && | 3157 | if (!br_idx) { /* user did not specify a specific bridge */ |
3160 | !(dev->priv_flags & IFF_EBRIDGE)) | 3158 | if (dev->priv_flags & IFF_BRIDGE_PORT) { |
3161 | continue; | 3159 | br_dev = netdev_master_upper_dev_get(dev); |
3160 | cops = br_dev->netdev_ops; | ||
3161 | } | ||
3162 | } else { | ||
3163 | if (dev != br_dev && | ||
3164 | !(dev->priv_flags & IFF_BRIDGE_PORT)) | ||
3165 | continue; | ||
3162 | 3166 | ||
3163 | cops = ops; | 3167 | if (br_dev != netdev_master_upper_dev_get(dev) && |
3164 | } | 3168 | !(dev->priv_flags & IFF_EBRIDGE)) |
3169 | continue; | ||
3170 | cops = ops; | ||
3171 | } | ||
3165 | 3172 | ||
3166 | if (dev->priv_flags & IFF_BRIDGE_PORT) { | 3173 | if (idx < s_idx) |
3167 | if (cops && cops->ndo_fdb_dump) | 3174 | goto cont; |
3168 | idx = cops->ndo_fdb_dump(skb, cb, br_dev, dev, | ||
3169 | idx); | ||
3170 | } | ||
3171 | if (cb->args[1] == -EMSGSIZE) | ||
3172 | break; | ||
3173 | 3175 | ||
3174 | if (dev->netdev_ops->ndo_fdb_dump) | 3176 | if (dev->priv_flags & IFF_BRIDGE_PORT) { |
3175 | idx = dev->netdev_ops->ndo_fdb_dump(skb, cb, dev, NULL, | 3177 | if (cops && cops->ndo_fdb_dump) { |
3176 | idx); | 3178 | err = cops->ndo_fdb_dump(skb, cb, |
3177 | else | 3179 | br_dev, dev, |
3178 | idx = ndo_dflt_fdb_dump(skb, cb, dev, NULL, idx); | 3180 | &fidx); |
3179 | if (cb->args[1] == -EMSGSIZE) | 3181 | if (err == -EMSGSIZE) |
3180 | break; | 3182 | goto out; |
3183 | } | ||
3184 | } | ||
3181 | 3185 | ||
3182 | cops = NULL; | 3186 | if (dev->netdev_ops->ndo_fdb_dump) |
3187 | err = dev->netdev_ops->ndo_fdb_dump(skb, cb, | ||
3188 | dev, NULL, | ||
3189 | &fidx); | ||
3190 | else | ||
3191 | err = ndo_dflt_fdb_dump(skb, cb, dev, NULL, | ||
3192 | &fidx); | ||
3193 | if (err == -EMSGSIZE) | ||
3194 | goto out; | ||
3195 | |||
3196 | cops = NULL; | ||
3197 | |||
3198 | /* reset fdb offset to 0 for rest of the interfaces */ | ||
3199 | cb->args[2] = 0; | ||
3200 | fidx = 0; | ||
3201 | cont: | ||
3202 | idx++; | ||
3203 | } | ||
3183 | } | 3204 | } |
3184 | 3205 | ||
3185 | cb->args[0] = idx; | 3206 | out: |
3207 | cb->args[0] = h; | ||
3208 | cb->args[1] = idx; | ||
3209 | cb->args[2] = fidx; | ||
3210 | |||
3186 | return skb->len; | 3211 | return skb->len; |
3187 | } | 3212 | } |
3188 | 3213 | ||
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c index 1031a0327fff..10b819308439 100644 --- a/net/switchdev/switchdev.c +++ b/net/switchdev/switchdev.c | |||
@@ -1042,7 +1042,7 @@ static int switchdev_port_fdb_dump_cb(struct switchdev_obj *obj) | |||
1042 | struct nlmsghdr *nlh; | 1042 | struct nlmsghdr *nlh; |
1043 | struct ndmsg *ndm; | 1043 | struct ndmsg *ndm; |
1044 | 1044 | ||
1045 | if (dump->idx < dump->cb->args[0]) | 1045 | if (dump->idx < dump->cb->args[2]) |
1046 | goto skip; | 1046 | goto skip; |
1047 | 1047 | ||
1048 | nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, | 1048 | nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH, |
@@ -1089,7 +1089,7 @@ nla_put_failure: | |||
1089 | */ | 1089 | */ |
1090 | int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, | 1090 | int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, |
1091 | struct net_device *dev, | 1091 | struct net_device *dev, |
1092 | struct net_device *filter_dev, int idx) | 1092 | struct net_device *filter_dev, int *idx) |
1093 | { | 1093 | { |
1094 | struct switchdev_fdb_dump dump = { | 1094 | struct switchdev_fdb_dump dump = { |
1095 | .fdb.obj.orig_dev = dev, | 1095 | .fdb.obj.orig_dev = dev, |
@@ -1097,14 +1097,14 @@ int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, | |||
1097 | .dev = dev, | 1097 | .dev = dev, |
1098 | .skb = skb, | 1098 | .skb = skb, |
1099 | .cb = cb, | 1099 | .cb = cb, |
1100 | .idx = idx, | 1100 | .idx = *idx, |
1101 | }; | 1101 | }; |
1102 | int err; | 1102 | int err; |
1103 | 1103 | ||
1104 | err = switchdev_port_obj_dump(dev, &dump.fdb.obj, | 1104 | err = switchdev_port_obj_dump(dev, &dump.fdb.obj, |
1105 | switchdev_port_fdb_dump_cb); | 1105 | switchdev_port_fdb_dump_cb); |
1106 | cb->args[1] = err; | 1106 | *idx = dump.idx; |
1107 | return dump.idx; | 1107 | return err; |
1108 | } | 1108 | } |
1109 | EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); | 1109 | EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); |
1110 | 1110 | ||