LCOV - code coverage report
Current view: top level - net/core - net-procfs.c (source / functions) Hit Total Coverage
Test: landlock.info Lines: 14 172 8.1 %
Date: 2021-04-22 12:43:58 Functions: 3 23 13.0 %

          Line data    Source code
       1             : // SPDX-License-Identifier: GPL-2.0
       2             : #include <linux/netdevice.h>
       3             : #include <linux/proc_fs.h>
       4             : #include <linux/seq_file.h>
       5             : #include <net/wext.h>
       6             : 
       7             : #define BUCKET_SPACE (32 - NETDEV_HASHBITS - 1)
       8             : 
       9             : #define get_bucket(x) ((x) >> BUCKET_SPACE)
      10             : #define get_offset(x) ((x) & ((1 << BUCKET_SPACE) - 1))
      11             : #define set_bucket_offset(b, o) ((b) << BUCKET_SPACE | (o))
      12             : 
      13             : extern struct list_head ptype_all __read_mostly;
      14             : extern struct list_head ptype_base[PTYPE_HASH_SIZE] __read_mostly;
      15             : 
      16           0 : static inline struct net_device *dev_from_same_bucket(struct seq_file *seq, loff_t *pos)
      17             : {
      18           0 :         struct net *net = seq_file_net(seq);
      19           0 :         struct net_device *dev;
      20           0 :         struct hlist_head *h;
      21           0 :         unsigned int count = 0, offset = get_offset(*pos);
      22             : 
      23           0 :         h = &net->dev_index_head[get_bucket(*pos)];
      24           0 :         hlist_for_each_entry_rcu(dev, h, index_hlist) {
      25           0 :                 if (++count == offset)
      26           0 :                         return dev;
      27             :         }
      28             : 
      29             :         return NULL;
      30             : }
      31             : 
      32           0 : static inline struct net_device *dev_from_bucket(struct seq_file *seq, loff_t *pos)
      33             : {
      34           0 :         struct net_device *dev;
      35           0 :         unsigned int bucket;
      36             : 
      37           0 :         do {
      38           0 :                 dev = dev_from_same_bucket(seq, pos);
      39           0 :                 if (dev)
      40           0 :                         return dev;
      41             : 
      42           0 :                 bucket = get_bucket(*pos) + 1;
      43           0 :                 *pos = set_bucket_offset(bucket, 1);
      44           0 :         } while (bucket < NETDEV_HASHENTRIES);
      45             : 
      46             :         return NULL;
      47             : }
      48             : 
      49             : /*
      50             :  *      This is invoked by the /proc filesystem handler to display a device
      51             :  *      in detail.
      52             :  */
      53           0 : static void *dev_seq_start(struct seq_file *seq, loff_t *pos)
      54             :         __acquires(RCU)
      55             : {
      56           0 :         rcu_read_lock();
      57           0 :         if (!*pos)
      58             :                 return SEQ_START_TOKEN;
      59             : 
      60           0 :         if (get_bucket(*pos) >= NETDEV_HASHENTRIES)
      61             :                 return NULL;
      62             : 
      63           0 :         return dev_from_bucket(seq, pos);
      64             : }
      65             : 
      66           0 : static void *dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
      67             : {
      68           0 :         ++*pos;
      69           0 :         return dev_from_bucket(seq, pos);
      70             : }
      71             : 
      72           0 : static void dev_seq_stop(struct seq_file *seq, void *v)
      73             :         __releases(RCU)
      74             : {
      75           0 :         rcu_read_unlock();
      76           0 : }
      77             : 
      78           0 : static void dev_seq_printf_stats(struct seq_file *seq, struct net_device *dev)
      79             : {
      80           0 :         struct rtnl_link_stats64 temp;
      81           0 :         const struct rtnl_link_stats64 *stats = dev_get_stats(dev, &temp);
      82             : 
      83           0 :         seq_printf(seq, "%6s: %7llu %7llu %4llu %4llu %4llu %5llu %10llu %9llu "
      84             :                    "%8llu %7llu %4llu %4llu %4llu %5llu %7llu %10llu\n",
      85           0 :                    dev->name, stats->rx_bytes, stats->rx_packets,
      86             :                    stats->rx_errors,
      87           0 :                    stats->rx_dropped + stats->rx_missed_errors,
      88             :                    stats->rx_fifo_errors,
      89           0 :                    stats->rx_length_errors + stats->rx_over_errors +
      90           0 :                     stats->rx_crc_errors + stats->rx_frame_errors,
      91             :                    stats->rx_compressed, stats->multicast,
      92             :                    stats->tx_bytes, stats->tx_packets,
      93             :                    stats->tx_errors, stats->tx_dropped,
      94             :                    stats->tx_fifo_errors, stats->collisions,
      95           0 :                    stats->tx_carrier_errors +
      96           0 :                     stats->tx_aborted_errors +
      97           0 :                     stats->tx_window_errors +
      98           0 :                     stats->tx_heartbeat_errors,
      99             :                    stats->tx_compressed);
     100           0 : }
     101             : 
     102             : /*
     103             :  *      Called from the PROCfs module. This now uses the new arbitrary sized
     104             :  *      /proc/net interface to create /proc/net/dev
     105             :  */
     106           0 : static int dev_seq_show(struct seq_file *seq, void *v)
     107             : {
     108           0 :         if (v == SEQ_START_TOKEN)
     109           0 :                 seq_puts(seq, "Inter-|   Receive                            "
     110             :                               "                    |  Transmit\n"
     111             :                               " face |bytes    packets errs drop fifo frame "
     112             :                               "compressed multicast|bytes    packets errs "
     113             :                               "drop fifo colls carrier compressed\n");
     114             :         else
     115           0 :                 dev_seq_printf_stats(seq, v);
     116           0 :         return 0;
     117             : }
     118             : 
     119           0 : static u32 softnet_backlog_len(struct softnet_data *sd)
     120             : {
     121           0 :         return skb_queue_len_lockless(&sd->input_pkt_queue) +
     122           0 :                skb_queue_len_lockless(&sd->process_queue);
     123             : }
     124             : 
     125           0 : static struct softnet_data *softnet_get_online(loff_t *pos)
     126             : {
     127           0 :         struct softnet_data *sd = NULL;
     128             : 
     129           0 :         while (*pos < nr_cpu_ids)
     130           0 :                 if (cpu_online(*pos)) {
     131           0 :                         sd = &per_cpu(softnet_data, *pos);
     132           0 :                         break;
     133             :                 } else
     134           0 :                         ++*pos;
     135           0 :         return sd;
     136             : }
     137             : 
     138           0 : static void *softnet_seq_start(struct seq_file *seq, loff_t *pos)
     139             : {
     140           0 :         return softnet_get_online(pos);
     141             : }
     142             : 
     143           0 : static void *softnet_seq_next(struct seq_file *seq, void *v, loff_t *pos)
     144             : {
     145           0 :         ++*pos;
     146           0 :         return softnet_get_online(pos);
     147             : }
     148             : 
     149           0 : static void softnet_seq_stop(struct seq_file *seq, void *v)
     150             : {
     151           0 : }
     152             : 
     153           0 : static int softnet_seq_show(struct seq_file *seq, void *v)
     154             : {
     155           0 :         struct softnet_data *sd = v;
     156           0 :         unsigned int flow_limit_count = 0;
     157             : 
     158             : #ifdef CONFIG_NET_FLOW_LIMIT
     159           0 :         struct sd_flow_limit *fl;
     160             : 
     161           0 :         rcu_read_lock();
     162           0 :         fl = rcu_dereference(sd->flow_limit);
     163           0 :         if (fl)
     164           0 :                 flow_limit_count = fl->count;
     165           0 :         rcu_read_unlock();
     166             : #endif
     167             : 
     168             :         /* the index is the CPU id owing this sd. Since offline CPUs are not
     169             :          * displayed, it would be othrwise not trivial for the user-space
     170             :          * mapping the data a specific CPU
     171             :          */
     172           0 :         seq_printf(seq,
     173             :                    "%08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x %08x\n",
     174             :                    sd->processed, sd->dropped, sd->time_squeeze, 0,
     175             :                    0, 0, 0, 0, /* was fastroute */
     176             :                    0,   /* was cpu_collision */
     177             :                    sd->received_rps, flow_limit_count,
     178           0 :                    softnet_backlog_len(sd), (int)seq->index);
     179           0 :         return 0;
     180             : }
     181             : 
     182             : static const struct seq_operations dev_seq_ops = {
     183             :         .start = dev_seq_start,
     184             :         .next  = dev_seq_next,
     185             :         .stop  = dev_seq_stop,
     186             :         .show  = dev_seq_show,
     187             : };
     188             : 
     189             : static const struct seq_operations softnet_seq_ops = {
     190             :         .start = softnet_seq_start,
     191             :         .next  = softnet_seq_next,
     192             :         .stop  = softnet_seq_stop,
     193             :         .show  = softnet_seq_show,
     194             : };
     195             : 
     196           0 : static void *ptype_get_idx(loff_t pos)
     197             : {
     198           0 :         struct packet_type *pt = NULL;
     199           0 :         loff_t i = 0;
     200           0 :         int t;
     201             : 
     202           0 :         list_for_each_entry_rcu(pt, &ptype_all, list) {
     203           0 :                 if (i == pos)
     204           0 :                         return pt;
     205           0 :                 ++i;
     206             :         }
     207             : 
     208           0 :         for (t = 0; t < PTYPE_HASH_SIZE; t++) {
     209           0 :                 list_for_each_entry_rcu(pt, &ptype_base[t], list) {
     210           0 :                         if (i == pos)
     211           0 :                                 return pt;
     212           0 :                         ++i;
     213             :                 }
     214             :         }
     215             :         return NULL;
     216             : }
     217             : 
     218           0 : static void *ptype_seq_start(struct seq_file *seq, loff_t *pos)
     219             :         __acquires(RCU)
     220             : {
     221           0 :         rcu_read_lock();
     222           0 :         return *pos ? ptype_get_idx(*pos - 1) : SEQ_START_TOKEN;
     223             : }
     224             : 
     225           0 : static void *ptype_seq_next(struct seq_file *seq, void *v, loff_t *pos)
     226             : {
     227           0 :         struct packet_type *pt;
     228           0 :         struct list_head *nxt;
     229           0 :         int hash;
     230             : 
     231           0 :         ++*pos;
     232           0 :         if (v == SEQ_START_TOKEN)
     233           0 :                 return ptype_get_idx(0);
     234             : 
     235           0 :         pt = v;
     236           0 :         nxt = pt->list.next;
     237           0 :         if (pt->type == htons(ETH_P_ALL)) {
     238           0 :                 if (nxt != &ptype_all)
     239           0 :                         goto found;
     240           0 :                 hash = 0;
     241           0 :                 nxt = ptype_base[0].next;
     242             :         } else
     243           0 :                 hash = ntohs(pt->type) & PTYPE_HASH_MASK;
     244             : 
     245           0 :         while (nxt == &ptype_base[hash]) {
     246           0 :                 if (++hash >= PTYPE_HASH_SIZE)
     247             :                         return NULL;
     248           0 :                 nxt = ptype_base[hash].next;
     249             :         }
     250           0 : found:
     251           0 :         return list_entry(nxt, struct packet_type, list);
     252             : }
     253             : 
     254           0 : static void ptype_seq_stop(struct seq_file *seq, void *v)
     255             :         __releases(RCU)
     256             : {
     257           0 :         rcu_read_unlock();
     258           0 : }
     259             : 
     260           0 : static int ptype_seq_show(struct seq_file *seq, void *v)
     261             : {
     262           0 :         struct packet_type *pt = v;
     263             : 
     264           0 :         if (v == SEQ_START_TOKEN)
     265           0 :                 seq_puts(seq, "Type Device      Function\n");
     266           0 :         else if (pt->dev == NULL || dev_net(pt->dev) == seq_file_net(seq)) {
     267           0 :                 if (pt->type == htons(ETH_P_ALL))
     268           0 :                         seq_puts(seq, "ALL ");
     269             :                 else
     270           0 :                         seq_printf(seq, "%04x", ntohs(pt->type));
     271             : 
     272           0 :                 seq_printf(seq, " %-8s %ps\n",
     273           0 :                            pt->dev ? pt->dev->name : "", pt->func);
     274             :         }
     275             : 
     276           0 :         return 0;
     277             : }
     278             : 
     279             : static const struct seq_operations ptype_seq_ops = {
     280             :         .start = ptype_seq_start,
     281             :         .next  = ptype_seq_next,
     282             :         .stop  = ptype_seq_stop,
     283             :         .show  = ptype_seq_show,
     284             : };
     285             : 
     286           1 : static int __net_init dev_proc_net_init(struct net *net)
     287             : {
     288           1 :         int rc = -ENOMEM;
     289             : 
     290           1 :         if (!proc_create_net("dev", 0444, net->proc_net, &dev_seq_ops,
     291             :                         sizeof(struct seq_net_private)))
     292           0 :                 goto out;
     293           1 :         if (!proc_create_seq("softnet_stat", 0444, net->proc_net,
     294             :                          &softnet_seq_ops))
     295           0 :                 goto out_dev;
     296           1 :         if (!proc_create_net("ptype", 0444, net->proc_net, &ptype_seq_ops,
     297             :                         sizeof(struct seq_net_private)))
     298           0 :                 goto out_softnet;
     299             : 
     300           1 :         if (wext_proc_init(net))
     301             :                 goto out_ptype;
     302             :         rc = 0;
     303           1 : out:
     304           1 :         return rc;
     305             : out_ptype:
     306             :         remove_proc_entry("ptype", net->proc_net);
     307           0 : out_softnet:
     308           0 :         remove_proc_entry("softnet_stat", net->proc_net);
     309           0 : out_dev:
     310           0 :         remove_proc_entry("dev", net->proc_net);
     311           0 :         goto out;
     312             : }
     313             : 
     314           0 : static void __net_exit dev_proc_net_exit(struct net *net)
     315             : {
     316           0 :         wext_proc_exit(net);
     317             : 
     318           0 :         remove_proc_entry("ptype", net->proc_net);
     319           0 :         remove_proc_entry("softnet_stat", net->proc_net);
     320           0 :         remove_proc_entry("dev", net->proc_net);
     321           0 : }
     322             : 
     323             : static struct pernet_operations __net_initdata dev_proc_ops = {
     324             :         .init = dev_proc_net_init,
     325             :         .exit = dev_proc_net_exit,
     326             : };
     327             : 
     328           0 : static int dev_mc_seq_show(struct seq_file *seq, void *v)
     329             : {
     330           0 :         struct netdev_hw_addr *ha;
     331           0 :         struct net_device *dev = v;
     332             : 
     333           0 :         if (v == SEQ_START_TOKEN)
     334             :                 return 0;
     335             : 
     336           0 :         netif_addr_lock_bh(dev);
     337           0 :         netdev_for_each_mc_addr(ha, dev) {
     338           0 :                 seq_printf(seq, "%-4d %-15s %-5d %-5d %*phN\n",
     339           0 :                            dev->ifindex, dev->name,
     340           0 :                            ha->refcount, ha->global_use,
     341           0 :                            (int)dev->addr_len, ha->addr);
     342             :         }
     343           0 :         netif_addr_unlock_bh(dev);
     344           0 :         return 0;
     345             : }
     346             : 
     347             : static const struct seq_operations dev_mc_seq_ops = {
     348             :         .start = dev_seq_start,
     349             :         .next  = dev_seq_next,
     350             :         .stop  = dev_seq_stop,
     351             :         .show  = dev_mc_seq_show,
     352             : };
     353             : 
     354           1 : static int __net_init dev_mc_net_init(struct net *net)
     355             : {
     356           1 :         if (!proc_create_net("dev_mcast", 0, net->proc_net, &dev_mc_seq_ops,
     357             :                         sizeof(struct seq_net_private)))
     358           0 :                 return -ENOMEM;
     359             :         return 0;
     360             : }
     361             : 
     362           0 : static void __net_exit dev_mc_net_exit(struct net *net)
     363             : {
     364           0 :         remove_proc_entry("dev_mcast", net->proc_net);
     365           0 : }
     366             : 
     367             : static struct pernet_operations __net_initdata dev_mc_net_ops = {
     368             :         .init = dev_mc_net_init,
     369             :         .exit = dev_mc_net_exit,
     370             : };
     371             : 
     372           1 : int __init dev_proc_init(void)
     373             : {
     374           1 :         int ret = register_pernet_subsys(&dev_proc_ops);
     375           1 :         if (!ret)
     376           1 :                 return register_pernet_subsys(&dev_mc_net_ops);
     377             :         return ret;
     378             : }

Generated by: LCOV version 1.14