@@ -771,10 +771,13 @@ static int dpaa2_switch_fdb_dump_nl(struct fdb_dump_entry *entry,
int is_dynamic = entry->type & DPSW_FDB_ENTRY_DINAMIC;
u32 portid = NETLINK_CB(dump->cb->skb).portid;
u32 seq = dump->cb->nlh->nlmsg_seq;
+ struct rtnl_fdb_dump_ctx *ctx;
struct nlmsghdr *nlh;
struct ndmsg *ndm;
- if (dump->idx < dump->cb->args[2])
+ ctx = (struct rtnl_fdb_dump_ctx *)dump->cb->ctx;
+
+ if (dump->idx < ctx->fidx)
goto skip;
nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH,
@@ -971,10 +971,13 @@ int ocelot_port_fdb_do_dump(const unsigned char *addr, u16 vid,
struct ocelot_dump_ctx *dump = data;
u32 portid = NETLINK_CB(dump->cb->skb).portid;
u32 seq = dump->cb->nlh->nlmsg_seq;
+ struct rtnl_fdb_dump_ctx *ctx;
struct nlmsghdr *nlh;
struct ndmsg *ndm;
- if (dump->idx < dump->cb->args[2])
+ ctx = (struct rtnl_fdb_dump_ctx *)dump->cb->ctx;
+
+ if (dump->idx < ctx->fidx)
goto skip;
nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH,
@@ -1371,6 +1371,7 @@ static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
struct net_device *dev,
struct net_device *filter_dev, int *idx)
{
+ struct rtnl_fdb_dump_ctx *ctx = (struct rtnl_fdb_dump_ctx *)cb->ctx;
struct vxlan_dev *vxlan = netdev_priv(dev);
unsigned int h;
int err = 0;
@@ -1383,7 +1384,7 @@ static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
struct vxlan_rdst *rd;
if (rcu_access_pointer(f->nh)) {
- if (*idx < cb->args[2])
+ if (*idx < ctx->fidx)
goto skip_nh;
err = vxlan_fdb_info(skb, vxlan, f,
NETLINK_CB(cb->skb).portid,
@@ -1400,7 +1401,7 @@ static int vxlan_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb,
}
list_for_each_entry_rcu(rd, &f->remotes, list) {
- if (*idx < cb->args[2])
+ if (*idx < ctx->fidx)
goto skip;
err = vxlan_fdb_info(skb, vxlan, f,
@@ -110,6 +110,24 @@ void rtnl_kfree_skbs(struct sk_buff *head, struct sk_buff *tail);
WARN_ONCE(!rtnl_is_locked(), \
"RTNL: assertion failed at %s (%d)\n", __FILE__, __LINE__)
+struct rtnl_fdb_dump_ctx {
+ /* Last bucket in the dev_index_head hash list that was checked.
+ * Used by rtnl_fdb_dump to resume in case the procedure is
+ * interrupted.
+ */
+ int pos_hash;
+ /* Last interface within bucket @pos_hash that was checked.
+ * Used by rtnl_fdb_dump to resume in case the procedure is
+ * interrupted.
+ */
+ int pos_idx;
+ /* Last FDB entry number that was dumped for the current interface.
+ * Updated by implementers of .ndo_fdb_dump and used to resume in case
+ * the dump procedure is interrupted.
+ */
+ int fidx;
+};
+
extern int ndo_dflt_fdb_dump(struct sk_buff *skb,
struct netlink_callback *cb,
struct net_device *dev,
@@ -821,6 +821,7 @@ int br_fdb_dump(struct sk_buff *skb,
struct net_device *filter_dev,
int *idx)
{
+ struct rtnl_fdb_dump_ctx *ctx = (struct rtnl_fdb_dump_ctx *)cb->ctx;
struct net_bridge *br = netdev_priv(dev);
struct net_bridge_fdb_entry *f;
int err = 0;
@@ -836,7 +837,7 @@ int br_fdb_dump(struct sk_buff *skb,
rcu_read_lock();
hlist_for_each_entry_rcu(f, &br->fdb_list, fdb_node) {
- if (*idx < cb->args[2])
+ if (*idx < ctx->fidx)
goto skip;
if (filter_dev && (!f->dst || f->dst->dev != filter_dev)) {
if (filter_dev != dev)
@@ -4184,6 +4184,7 @@ static int nlmsg_populate_fdb(struct sk_buff *skb,
int *idx,
struct netdev_hw_addr_list *list)
{
+ struct rtnl_fdb_dump_ctx *ctx = (struct rtnl_fdb_dump_ctx *)cb->ctx;
struct netdev_hw_addr *ha;
int err;
u32 portid, seq;
@@ -4192,7 +4193,7 @@ static int nlmsg_populate_fdb(struct sk_buff *skb,
seq = cb->nlh->nlmsg_seq;
list_for_each_entry(ha, &list->list, list) {
- if (*idx < cb->args[2])
+ if (*idx < ctx->fidx)
goto skip;
err = nlmsg_populate_fdb_fill(skb, dev, ha->addr, 0,
@@ -4331,6 +4332,7 @@ static int valid_fdb_dump_legacy(const struct nlmsghdr *nlh,
static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
{
+ struct rtnl_fdb_dump_ctx *ctx = (struct rtnl_fdb_dump_ctx *)cb->ctx;
struct net_device *dev;
struct net_device *br_dev = NULL;
const struct net_device_ops *ops = NULL;
@@ -4361,8 +4363,8 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
ops = br_dev->netdev_ops;
}
- s_h = cb->args[0];
- s_idx = cb->args[1];
+ s_h = ctx->pos_hash;
+ s_idx = ctx->pos_idx;
for (h = s_h; h < NETDEV_HASHENTRIES; h++, s_idx = 0) {
idx = 0;
@@ -4414,7 +4416,7 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
cops = NULL;
/* reset fdb offset to 0 for rest of the interfaces */
- cb->args[2] = 0;
+ ctx->fidx = 0;
fidx = 0;
cont:
idx++;
@@ -4422,9 +4424,9 @@ static int rtnl_fdb_dump(struct sk_buff *skb, struct netlink_callback *cb)
}
out:
- cb->args[0] = h;
- cb->args[1] = idx;
- cb->args[2] = fidx;
+ ctx->pos_hash = h;
+ ctx->pos_idx = idx;
+ ctx->fidx = fidx;
return skb->len;
}
@@ -193,10 +193,13 @@ dsa_slave_port_fdb_do_dump(const unsigned char *addr, u16 vid,
struct dsa_slave_dump_ctx *dump = data;
u32 portid = NETLINK_CB(dump->cb->skb).portid;
u32 seq = dump->cb->nlh->nlmsg_seq;
+ struct rtnl_fdb_dump_ctx *ctx;
struct nlmsghdr *nlh;
struct ndmsg *ndm;
- if (dump->idx < dump->cb->args[2])
+ ctx = (struct rtnl_fdb_dump_ctx *)dump->cb->ctx;
+
+ if (dump->idx < ctx->fidx)
goto skip;
nlh = nlmsg_put(dump->skb, portid, seq, RTM_NEWNEIGH,
For the ability to grep for proper structure/variable names, if for nothing else, use the more modern struct netlink_callback::ctx as opposed to args to hold the stateful data over the course of an FDB dump operation. Signed-off-by: Vladimir Oltean <vladimir.oltean@nxp.com> --- .../ethernet/freescale/dpaa2/dpaa2-switch.c | 5 ++++- drivers/net/ethernet/mscc/ocelot.c | 5 ++++- drivers/net/vxlan.c | 5 +++-- include/linux/rtnetlink.h | 18 ++++++++++++++++++ net/bridge/br_fdb.c | 3 ++- net/core/rtnetlink.c | 16 +++++++++------- net/dsa/slave.c | 5 ++++- 7 files changed, 44 insertions(+), 13 deletions(-)