0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 #include <linux/module.h>
0044 #include <linux/proc_fs.h>
0045 #include <linux/list.h>
0046 #include <linux/rcupdate.h>
0047 #include <linux/if_arp.h>
0048 #include <linux/can/can-ml.h>
0049 #include <linux/can/core.h>
0050
0051 #include "af_can.h"
0052
0053
0054
0055
0056
0057 #define CAN_PROC_STATS "stats"
0058 #define CAN_PROC_RESET_STATS "reset_stats"
0059 #define CAN_PROC_RCVLIST_ALL "rcvlist_all"
0060 #define CAN_PROC_RCVLIST_FIL "rcvlist_fil"
0061 #define CAN_PROC_RCVLIST_INV "rcvlist_inv"
0062 #define CAN_PROC_RCVLIST_SFF "rcvlist_sff"
0063 #define CAN_PROC_RCVLIST_EFF "rcvlist_eff"
0064 #define CAN_PROC_RCVLIST_ERR "rcvlist_err"
0065
0066 static int user_reset;
0067
0068 static const char rx_list_name[][8] = {
0069 [RX_ERR] = "rx_err",
0070 [RX_ALL] = "rx_all",
0071 [RX_FIL] = "rx_fil",
0072 [RX_INV] = "rx_inv",
0073 };
0074
0075
0076
0077
0078
0079 static void can_init_stats(struct net *net)
0080 {
0081 struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
0082 struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
0083
0084
0085
0086
0087
0088 memset(pkg_stats, 0, sizeof(struct can_pkg_stats));
0089 pkg_stats->jiffies_init = jiffies;
0090
0091 rcv_lists_stats->stats_reset++;
0092
0093 if (user_reset) {
0094 user_reset = 0;
0095 rcv_lists_stats->user_reset++;
0096 }
0097 }
0098
0099 static unsigned long calc_rate(unsigned long oldjif, unsigned long newjif,
0100 unsigned long count)
0101 {
0102 if (oldjif == newjif)
0103 return 0;
0104
0105
0106 if (count > (ULONG_MAX / HZ)) {
0107 printk(KERN_ERR "can: calc_rate: count exceeded! %ld\n",
0108 count);
0109 return 99999999;
0110 }
0111
0112 return (count * HZ) / (newjif - oldjif);
0113 }
0114
0115 void can_stat_update(struct timer_list *t)
0116 {
0117 struct net *net = from_timer(net, t, can.stattimer);
0118 struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
0119 unsigned long j = jiffies;
0120
0121
0122 if (user_reset)
0123 can_init_stats(net);
0124
0125
0126 if (j < pkg_stats->jiffies_init)
0127 can_init_stats(net);
0128
0129
0130 if (pkg_stats->rx_frames > (ULONG_MAX / HZ))
0131 can_init_stats(net);
0132
0133
0134 if (pkg_stats->tx_frames > (ULONG_MAX / HZ))
0135 can_init_stats(net);
0136
0137
0138 if (pkg_stats->matches > (ULONG_MAX / 100))
0139 can_init_stats(net);
0140
0141
0142 if (pkg_stats->rx_frames)
0143 pkg_stats->total_rx_match_ratio = (pkg_stats->matches * 100) /
0144 pkg_stats->rx_frames;
0145
0146 pkg_stats->total_tx_rate = calc_rate(pkg_stats->jiffies_init, j,
0147 pkg_stats->tx_frames);
0148 pkg_stats->total_rx_rate = calc_rate(pkg_stats->jiffies_init, j,
0149 pkg_stats->rx_frames);
0150
0151
0152 if (pkg_stats->rx_frames_delta)
0153 pkg_stats->current_rx_match_ratio =
0154 (pkg_stats->matches_delta * 100) /
0155 pkg_stats->rx_frames_delta;
0156
0157 pkg_stats->current_tx_rate = calc_rate(0, HZ, pkg_stats->tx_frames_delta);
0158 pkg_stats->current_rx_rate = calc_rate(0, HZ, pkg_stats->rx_frames_delta);
0159
0160
0161 if (pkg_stats->max_tx_rate < pkg_stats->current_tx_rate)
0162 pkg_stats->max_tx_rate = pkg_stats->current_tx_rate;
0163
0164 if (pkg_stats->max_rx_rate < pkg_stats->current_rx_rate)
0165 pkg_stats->max_rx_rate = pkg_stats->current_rx_rate;
0166
0167 if (pkg_stats->max_rx_match_ratio < pkg_stats->current_rx_match_ratio)
0168 pkg_stats->max_rx_match_ratio = pkg_stats->current_rx_match_ratio;
0169
0170
0171 pkg_stats->tx_frames_delta = 0;
0172 pkg_stats->rx_frames_delta = 0;
0173 pkg_stats->matches_delta = 0;
0174
0175
0176 mod_timer(&net->can.stattimer, round_jiffies(jiffies + HZ));
0177 }
0178
0179
0180
0181
0182
0183 static void can_print_rcvlist(struct seq_file *m, struct hlist_head *rx_list,
0184 struct net_device *dev)
0185 {
0186 struct receiver *r;
0187
0188 hlist_for_each_entry_rcu(r, rx_list, list) {
0189 char *fmt = (r->can_id & CAN_EFF_FLAG)?
0190 " %-5s %08x %08x %pK %pK %8ld %s\n" :
0191 " %-5s %03x %08x %pK %pK %8ld %s\n";
0192
0193 seq_printf(m, fmt, DNAME(dev), r->can_id, r->mask,
0194 r->func, r->data, r->matches, r->ident);
0195 }
0196 }
0197
0198 static void can_print_recv_banner(struct seq_file *m)
0199 {
0200
0201
0202
0203
0204 if (IS_ENABLED(CONFIG_64BIT))
0205 seq_puts(m, " device can_id can_mask function userdata matches ident\n");
0206 else
0207 seq_puts(m, " device can_id can_mask function userdata matches ident\n");
0208 }
0209
0210 static int can_stats_proc_show(struct seq_file *m, void *v)
0211 {
0212 struct net *net = m->private;
0213 struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
0214 struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
0215
0216 seq_putc(m, '\n');
0217 seq_printf(m, " %8ld transmitted frames (TXF)\n", pkg_stats->tx_frames);
0218 seq_printf(m, " %8ld received frames (RXF)\n", pkg_stats->rx_frames);
0219 seq_printf(m, " %8ld matched frames (RXMF)\n", pkg_stats->matches);
0220
0221 seq_putc(m, '\n');
0222
0223 if (net->can.stattimer.function == can_stat_update) {
0224 seq_printf(m, " %8ld %% total match ratio (RXMR)\n",
0225 pkg_stats->total_rx_match_ratio);
0226
0227 seq_printf(m, " %8ld frames/s total tx rate (TXR)\n",
0228 pkg_stats->total_tx_rate);
0229 seq_printf(m, " %8ld frames/s total rx rate (RXR)\n",
0230 pkg_stats->total_rx_rate);
0231
0232 seq_putc(m, '\n');
0233
0234 seq_printf(m, " %8ld %% current match ratio (CRXMR)\n",
0235 pkg_stats->current_rx_match_ratio);
0236
0237 seq_printf(m, " %8ld frames/s current tx rate (CTXR)\n",
0238 pkg_stats->current_tx_rate);
0239 seq_printf(m, " %8ld frames/s current rx rate (CRXR)\n",
0240 pkg_stats->current_rx_rate);
0241
0242 seq_putc(m, '\n');
0243
0244 seq_printf(m, " %8ld %% max match ratio (MRXMR)\n",
0245 pkg_stats->max_rx_match_ratio);
0246
0247 seq_printf(m, " %8ld frames/s max tx rate (MTXR)\n",
0248 pkg_stats->max_tx_rate);
0249 seq_printf(m, " %8ld frames/s max rx rate (MRXR)\n",
0250 pkg_stats->max_rx_rate);
0251
0252 seq_putc(m, '\n');
0253 }
0254
0255 seq_printf(m, " %8ld current receive list entries (CRCV)\n",
0256 rcv_lists_stats->rcv_entries);
0257 seq_printf(m, " %8ld maximum receive list entries (MRCV)\n",
0258 rcv_lists_stats->rcv_entries_max);
0259
0260 if (rcv_lists_stats->stats_reset)
0261 seq_printf(m, "\n %8ld statistic resets (STR)\n",
0262 rcv_lists_stats->stats_reset);
0263
0264 if (rcv_lists_stats->user_reset)
0265 seq_printf(m, " %8ld user statistic resets (USTR)\n",
0266 rcv_lists_stats->user_reset);
0267
0268 seq_putc(m, '\n');
0269 return 0;
0270 }
0271
0272 static int can_reset_stats_proc_show(struct seq_file *m, void *v)
0273 {
0274 struct net *net = m->private;
0275 struct can_rcv_lists_stats *rcv_lists_stats = net->can.rcv_lists_stats;
0276 struct can_pkg_stats *pkg_stats = net->can.pkg_stats;
0277
0278 user_reset = 1;
0279
0280 if (net->can.stattimer.function == can_stat_update) {
0281 seq_printf(m, "Scheduled statistic reset #%ld.\n",
0282 rcv_lists_stats->stats_reset + 1);
0283 } else {
0284 if (pkg_stats->jiffies_init != jiffies)
0285 can_init_stats(net);
0286
0287 seq_printf(m, "Performed statistic reset #%ld.\n",
0288 rcv_lists_stats->stats_reset);
0289 }
0290 return 0;
0291 }
0292
0293 static inline void can_rcvlist_proc_show_one(struct seq_file *m, int idx,
0294 struct net_device *dev,
0295 struct can_dev_rcv_lists *dev_rcv_lists)
0296 {
0297 if (!hlist_empty(&dev_rcv_lists->rx[idx])) {
0298 can_print_recv_banner(m);
0299 can_print_rcvlist(m, &dev_rcv_lists->rx[idx], dev);
0300 } else
0301 seq_printf(m, " (%s: no entry)\n", DNAME(dev));
0302
0303 }
0304
0305 static int can_rcvlist_proc_show(struct seq_file *m, void *v)
0306 {
0307
0308 int idx = (int)(long)pde_data(m->file->f_inode);
0309 struct net_device *dev;
0310 struct can_dev_rcv_lists *dev_rcv_lists;
0311 struct net *net = m->private;
0312
0313 seq_printf(m, "\nreceive list '%s':\n", rx_list_name[idx]);
0314
0315 rcu_read_lock();
0316
0317
0318 dev_rcv_lists = net->can.rx_alldev_list;
0319 can_rcvlist_proc_show_one(m, idx, NULL, dev_rcv_lists);
0320
0321
0322 for_each_netdev_rcu(net, dev) {
0323 struct can_ml_priv *can_ml = can_get_ml_priv(dev);
0324
0325 if (can_ml)
0326 can_rcvlist_proc_show_one(m, idx, dev,
0327 &can_ml->dev_rcv_lists);
0328 }
0329
0330 rcu_read_unlock();
0331
0332 seq_putc(m, '\n');
0333 return 0;
0334 }
0335
0336 static inline void can_rcvlist_proc_show_array(struct seq_file *m,
0337 struct net_device *dev,
0338 struct hlist_head *rcv_array,
0339 unsigned int rcv_array_sz)
0340 {
0341 unsigned int i;
0342 int all_empty = 1;
0343
0344
0345 for (i = 0; i < rcv_array_sz; i++)
0346 if (!hlist_empty(&rcv_array[i])) {
0347 all_empty = 0;
0348 break;
0349 }
0350
0351 if (!all_empty) {
0352 can_print_recv_banner(m);
0353 for (i = 0; i < rcv_array_sz; i++) {
0354 if (!hlist_empty(&rcv_array[i]))
0355 can_print_rcvlist(m, &rcv_array[i], dev);
0356 }
0357 } else
0358 seq_printf(m, " (%s: no entry)\n", DNAME(dev));
0359 }
0360
0361 static int can_rcvlist_sff_proc_show(struct seq_file *m, void *v)
0362 {
0363 struct net_device *dev;
0364 struct can_dev_rcv_lists *dev_rcv_lists;
0365 struct net *net = m->private;
0366
0367
0368 seq_puts(m, "\nreceive list 'rx_sff':\n");
0369
0370 rcu_read_lock();
0371
0372
0373 dev_rcv_lists = net->can.rx_alldev_list;
0374 can_rcvlist_proc_show_array(m, NULL, dev_rcv_lists->rx_sff,
0375 ARRAY_SIZE(dev_rcv_lists->rx_sff));
0376
0377
0378 for_each_netdev_rcu(net, dev) {
0379 struct can_ml_priv *can_ml = can_get_ml_priv(dev);
0380
0381 if (can_ml) {
0382 dev_rcv_lists = &can_ml->dev_rcv_lists;
0383 can_rcvlist_proc_show_array(m, dev, dev_rcv_lists->rx_sff,
0384 ARRAY_SIZE(dev_rcv_lists->rx_sff));
0385 }
0386 }
0387
0388 rcu_read_unlock();
0389
0390 seq_putc(m, '\n');
0391 return 0;
0392 }
0393
0394 static int can_rcvlist_eff_proc_show(struct seq_file *m, void *v)
0395 {
0396 struct net_device *dev;
0397 struct can_dev_rcv_lists *dev_rcv_lists;
0398 struct net *net = m->private;
0399
0400
0401 seq_puts(m, "\nreceive list 'rx_eff':\n");
0402
0403 rcu_read_lock();
0404
0405
0406 dev_rcv_lists = net->can.rx_alldev_list;
0407 can_rcvlist_proc_show_array(m, NULL, dev_rcv_lists->rx_eff,
0408 ARRAY_SIZE(dev_rcv_lists->rx_eff));
0409
0410
0411 for_each_netdev_rcu(net, dev) {
0412 struct can_ml_priv *can_ml = can_get_ml_priv(dev);
0413
0414 if (can_ml) {
0415 dev_rcv_lists = &can_ml->dev_rcv_lists;
0416 can_rcvlist_proc_show_array(m, dev, dev_rcv_lists->rx_eff,
0417 ARRAY_SIZE(dev_rcv_lists->rx_eff));
0418 }
0419 }
0420
0421 rcu_read_unlock();
0422
0423 seq_putc(m, '\n');
0424 return 0;
0425 }
0426
0427
0428
0429
0430 void can_init_proc(struct net *net)
0431 {
0432
0433 net->can.proc_dir = proc_net_mkdir(net, "can", net->proc_net);
0434
0435 if (!net->can.proc_dir) {
0436 printk(KERN_INFO "can: failed to create /proc/net/can . "
0437 "CONFIG_PROC_FS missing?\n");
0438 return;
0439 }
0440
0441
0442 net->can.pde_stats = proc_create_net_single(CAN_PROC_STATS, 0644,
0443 net->can.proc_dir, can_stats_proc_show, NULL);
0444 net->can.pde_reset_stats = proc_create_net_single(CAN_PROC_RESET_STATS,
0445 0644, net->can.proc_dir, can_reset_stats_proc_show,
0446 NULL);
0447 net->can.pde_rcvlist_err = proc_create_net_single(CAN_PROC_RCVLIST_ERR,
0448 0644, net->can.proc_dir, can_rcvlist_proc_show,
0449 (void *)RX_ERR);
0450 net->can.pde_rcvlist_all = proc_create_net_single(CAN_PROC_RCVLIST_ALL,
0451 0644, net->can.proc_dir, can_rcvlist_proc_show,
0452 (void *)RX_ALL);
0453 net->can.pde_rcvlist_fil = proc_create_net_single(CAN_PROC_RCVLIST_FIL,
0454 0644, net->can.proc_dir, can_rcvlist_proc_show,
0455 (void *)RX_FIL);
0456 net->can.pde_rcvlist_inv = proc_create_net_single(CAN_PROC_RCVLIST_INV,
0457 0644, net->can.proc_dir, can_rcvlist_proc_show,
0458 (void *)RX_INV);
0459 net->can.pde_rcvlist_eff = proc_create_net_single(CAN_PROC_RCVLIST_EFF,
0460 0644, net->can.proc_dir, can_rcvlist_eff_proc_show, NULL);
0461 net->can.pde_rcvlist_sff = proc_create_net_single(CAN_PROC_RCVLIST_SFF,
0462 0644, net->can.proc_dir, can_rcvlist_sff_proc_show, NULL);
0463 }
0464
0465
0466
0467
0468 void can_remove_proc(struct net *net)
0469 {
0470 if (!net->can.proc_dir)
0471 return;
0472
0473 if (net->can.pde_stats)
0474 remove_proc_entry(CAN_PROC_STATS, net->can.proc_dir);
0475
0476 if (net->can.pde_reset_stats)
0477 remove_proc_entry(CAN_PROC_RESET_STATS, net->can.proc_dir);
0478
0479 if (net->can.pde_rcvlist_err)
0480 remove_proc_entry(CAN_PROC_RCVLIST_ERR, net->can.proc_dir);
0481
0482 if (net->can.pde_rcvlist_all)
0483 remove_proc_entry(CAN_PROC_RCVLIST_ALL, net->can.proc_dir);
0484
0485 if (net->can.pde_rcvlist_fil)
0486 remove_proc_entry(CAN_PROC_RCVLIST_FIL, net->can.proc_dir);
0487
0488 if (net->can.pde_rcvlist_inv)
0489 remove_proc_entry(CAN_PROC_RCVLIST_INV, net->can.proc_dir);
0490
0491 if (net->can.pde_rcvlist_eff)
0492 remove_proc_entry(CAN_PROC_RCVLIST_EFF, net->can.proc_dir);
0493
0494 if (net->can.pde_rcvlist_sff)
0495 remove_proc_entry(CAN_PROC_RCVLIST_SFF, net->can.proc_dir);
0496
0497 remove_proc_entry("can", net->proc_net);
0498 }