net-procfs: show net devices bound packet types

After commit:7866a621043f ("dev: add per net_device packet type chains"),
we can not get packet types that are bound to a specified net device by
/proc/net/ptype, this patch fix the regression.

Run "tcpdump -i ens192 udp -nns0" Before and after apply this patch:

Before:
  [root@localhost ~]# cat /proc/net/ptype
  Type Device      Function
  0800          ip_rcv
  0806          arp_rcv
  86dd          ipv6_rcv

After:
  [root@localhost ~]# cat /proc/net/ptype
  Type Device      Function
  ALL  ens192   tpacket_rcv
  0800          ip_rcv
  0806          arp_rcv
  86dd          ipv6_rcv

v1 -> v2:
  - fix the regression rather than adding new /proc API as
    suggested by Stephen Hemminger.

Fixes: 7866a62104 ("dev: add per net_device packet type chains")
Signed-off-by: Jianguo Wu <wujianguo@chinatelecom.cn>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Jianguo Wu 2022-01-21 17:15:31 +08:00 committed by David S. Miller
parent aa6034678e
commit 1d10f8a1f4
1 changed files with 32 additions and 3 deletions

View File

@ -190,12 +190,23 @@ static const struct seq_operations softnet_seq_ops = {
.show = softnet_seq_show, .show = softnet_seq_show,
}; };
static void *ptype_get_idx(loff_t pos) static void *ptype_get_idx(struct seq_file *seq, loff_t pos)
{ {
struct list_head *ptype_list = NULL;
struct packet_type *pt = NULL; struct packet_type *pt = NULL;
struct net_device *dev;
loff_t i = 0; loff_t i = 0;
int t; int t;
for_each_netdev_rcu(seq_file_net(seq), dev) {
ptype_list = &dev->ptype_all;
list_for_each_entry_rcu(pt, ptype_list, list) {
if (i == pos)
return pt;
++i;
}
}
list_for_each_entry_rcu(pt, &ptype_all, list) { list_for_each_entry_rcu(pt, &ptype_all, list) {
if (i == pos) if (i == pos)
return pt; return pt;
@ -216,22 +227,40 @@ static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
__acquires(RCU) __acquires(RCU)
{ {
rcu_read_lock(); rcu_read_lock();
return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN; return *pos ? ptype_get_idx(seq, *pos - 1) : SEQ_START_TOKEN;
} }
static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos) static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
{ {
struct net_device *dev;
struct packet_type *pt; struct packet_type *pt;
struct list_head *nxt; struct list_head *nxt;
int hash; int hash;
++*pos; ++*pos;
if (v == SEQ_START_TOKEN) if (v == SEQ_START_TOKEN)
return ptype_get_idx(0); return ptype_get_idx(seq, 0);
pt = v; pt = v;
nxt = pt->list.next; nxt = pt->list.next;
if (pt->dev) {
if (nxt != &pt->dev->ptype_all)
goto found;
dev = pt->dev;
for_each_netdev_continue_rcu(seq_file_net(seq), dev) {
if (!list_empty(&dev->ptype_all)) {
nxt = dev->ptype_all.next;
goto found;
}
}
nxt = ptype_all.next;
goto ptype_all;
}
if (pt->type == htons(ETH_P_ALL)) { if (pt->type == htons(ETH_P_ALL)) {
ptype_all:
if (nxt != &ptype_all) if (nxt != &ptype_all)
goto found; goto found;
hash = 0; hash = 0;