summaryrefslogtreecommitdiffstats
path: root/net
diff options
context:
space:
mode:
Diffstat (limited to 'net')
-rw-r--r--net/bridge/br_fdb.c23
-rw-r--r--net/bridge/br_private.h2
-rw-r--r--net/core/rtnetlink.c105
-rw-r--r--net/switchdev/switchdev.c10
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 }
757skip: 758skip:
758 ++idx; 759 *idx += 1;
759 } 760 }
760 } 761 }
761 762
762out: 763out:
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[],
508int br_fdb_add(struct ndmsg *nlh, struct nlattr *tb[], struct net_device *dev, 508int 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);
510int br_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, 510int 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);
512int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p); 512int br_fdb_sync_static(struct net_bridge *br, struct net_bridge_port *p);
513void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p); 513void br_fdb_unsync_static(struct net_bridge *br, struct net_bridge_port *p);
514int br_fdb_external_learn_add(struct net_bridge *br, struct net_bridge_port *p, 514int 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);
3107out: 3107out:
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}
3112EXPORT_SYMBOL(ndo_dflt_fdb_dump); 3111EXPORT_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;
3201cont:
3202 idx++;
3203 }
3183 } 3204 }
3184 3205
3185 cb->args[0] = idx; 3206out:
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 */
1090int switchdev_port_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb, 1090int 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}
1109EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump); 1109EXPORT_SYMBOL_GPL(switchdev_port_fdb_dump);
1110 1110