aboutsummaryrefslogtreecommitdiffstats
path: root/net/can
diff options
context:
space:
mode:
authorOliver Hartkopp <socketcan@hartkopp.net>2014-04-02 14:25:26 -0400
committerMarc Kleine-Budde <mkl@pengutronix.de>2014-05-19 03:38:24 -0400
commit45c700291aee5170185bf5d1c2a494b1e3fe0883 (patch)
tree296c18dc3657954ecf84a51c588046e855f2d9cd /net/can
parente3d3917f3d8f624a8df567b581fd8c4da49b443f (diff)
can: add hash based access to single EFF frame filters
In contrast to the direct access to the single SFF frame filters (which are indexed by the SFF CAN ID itself) the single EFF frame filters are arranged in a single linked hlist. To reduce the hlist traversal in the case of many filter subscriptions a hash based access is introduced for single EFF filters. Signed-off-by: Oliver Hartkopp <socketcan@hartkopp.net> Signed-off-by: Marc Kleine-Budde <mkl@pengutronix.de>
Diffstat (limited to 'net/can')
-rw-r--r--net/can/af_can.c31
-rw-r--r--net/can/af_can.h5
-rw-r--r--net/can/proc.c48
3 files changed, 75 insertions, 9 deletions
diff --git a/net/can/af_can.c b/net/can/af_can.c
index a27f8aad9e99..ce82337521f6 100644
--- a/net/can/af_can.c
+++ b/net/can/af_can.c
@@ -338,6 +338,29 @@ static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
338} 338}
339 339
340/** 340/**
341 * effhash - hash function for 29 bit CAN identifier reduction
342 * @can_id: 29 bit CAN identifier
343 *
344 * Description:
345 * To reduce the linear traversal in one linked list of _single_ EFF CAN
346 * frame subscriptions the 29 bit identifier is mapped to 10 bits.
347 * (see CAN_EFF_RCV_HASH_BITS definition)
348 *
349 * Return:
350 * Hash value from 0x000 - 0x3FF ( enforced by CAN_EFF_RCV_HASH_BITS mask )
351 */
352static unsigned int effhash(canid_t can_id)
353{
354 unsigned int hash;
355
356 hash = can_id;
357 hash ^= can_id >> CAN_EFF_RCV_HASH_BITS;
358 hash ^= can_id >> (2 * CAN_EFF_RCV_HASH_BITS);
359
360 return hash & ((1 << CAN_EFF_RCV_HASH_BITS) - 1);
361}
362
363/**
341 * find_rcv_list - determine optimal filterlist inside device filter struct 364 * find_rcv_list - determine optimal filterlist inside device filter struct
342 * @can_id: pointer to CAN identifier of a given can_filter 365 * @can_id: pointer to CAN identifier of a given can_filter
343 * @mask: pointer to CAN mask of a given can_filter 366 * @mask: pointer to CAN mask of a given can_filter
@@ -400,10 +423,8 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
400 !(*can_id & CAN_RTR_FLAG)) { 423 !(*can_id & CAN_RTR_FLAG)) {
401 424
402 if (*can_id & CAN_EFF_FLAG) { 425 if (*can_id & CAN_EFF_FLAG) {
403 if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS)) { 426 if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS))
404 /* RFC: a future use-case for hash-tables? */ 427 return &d->rx_eff[effhash(*can_id)];
405 return &d->rx[RX_EFF];
406 }
407 } else { 428 } else {
408 if (*mask == (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS)) 429 if (*mask == (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS))
409 return &d->rx_sff[*can_id]; 430 return &d->rx_sff[*can_id];
@@ -632,7 +653,7 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
632 return matches; 653 return matches;
633 654
634 if (can_id & CAN_EFF_FLAG) { 655 if (can_id & CAN_EFF_FLAG) {
635 hlist_for_each_entry_rcu(r, &d->rx[RX_EFF], list) { 656 hlist_for_each_entry_rcu(r, &d->rx_eff[effhash(can_id)], list) {
636 if (r->can_id == can_id) { 657 if (r->can_id == can_id) {
637 deliver(skb, r); 658 deliver(skb, r);
638 matches++; 659 matches++;
diff --git a/net/can/af_can.h b/net/can/af_can.h
index b4bdaa32d7a4..fca0fe9fc45a 100644
--- a/net/can/af_can.h
+++ b/net/can/af_can.h
@@ -60,13 +60,16 @@ struct receiver {
60}; 60};
61 61
62#define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS) 62#define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
63#define CAN_EFF_RCV_HASH_BITS 10
64#define CAN_EFF_RCV_ARRAY_SZ (1 << CAN_EFF_RCV_HASH_BITS)
63 65
64enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX }; 66enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_MAX };
65 67
66/* per device receive filters linked at dev->ml_priv */ 68/* per device receive filters linked at dev->ml_priv */
67struct dev_rcv_lists { 69struct dev_rcv_lists {
68 struct hlist_head rx[RX_MAX]; 70 struct hlist_head rx[RX_MAX];
69 struct hlist_head rx_sff[CAN_SFF_RCV_ARRAY_SZ]; 71 struct hlist_head rx_sff[CAN_SFF_RCV_ARRAY_SZ];
72 struct hlist_head rx_eff[CAN_EFF_RCV_ARRAY_SZ];
70 int remove_on_zero_entries; 73 int remove_on_zero_entries;
71 int entries; 74 int entries;
72}; 75};
diff --git a/net/can/proc.c b/net/can/proc.c
index 1621e5909ee6..1a19b985a868 100644
--- a/net/can/proc.c
+++ b/net/can/proc.c
@@ -80,7 +80,6 @@ static const char rx_list_name[][8] = {
80 [RX_ALL] = "rx_all", 80 [RX_ALL] = "rx_all",
81 [RX_FIL] = "rx_fil", 81 [RX_FIL] = "rx_fil",
82 [RX_INV] = "rx_inv", 82 [RX_INV] = "rx_inv",
83 [RX_EFF] = "rx_eff",
84}; 83};
85 84
86/* 85/*
@@ -456,6 +455,49 @@ static const struct file_operations can_rcvlist_sff_proc_fops = {
456 .release = single_release, 455 .release = single_release,
457}; 456};
458 457
458
459static int can_rcvlist_eff_proc_show(struct seq_file *m, void *v)
460{
461 struct net_device *dev;
462 struct dev_rcv_lists *d;
463
464 /* RX_EFF */
465 seq_puts(m, "\nreceive list 'rx_eff':\n");
466
467 rcu_read_lock();
468
469 /* eff receive list for 'all' CAN devices (dev == NULL) */
470 d = &can_rx_alldev_list;
471 can_rcvlist_proc_show_array(m, NULL, d->rx_eff, ARRAY_SIZE(d->rx_eff));
472
473 /* eff receive list for registered CAN devices */
474 for_each_netdev_rcu(&init_net, dev) {
475 if (dev->type == ARPHRD_CAN && dev->ml_priv) {
476 d = dev->ml_priv;
477 can_rcvlist_proc_show_array(m, dev, d->rx_eff,
478 ARRAY_SIZE(d->rx_eff));
479 }
480 }
481
482 rcu_read_unlock();
483
484 seq_putc(m, '\n');
485 return 0;
486}
487
488static int can_rcvlist_eff_proc_open(struct inode *inode, struct file *file)
489{
490 return single_open(file, can_rcvlist_eff_proc_show, NULL);
491}
492
493static const struct file_operations can_rcvlist_eff_proc_fops = {
494 .owner = THIS_MODULE,
495 .open = can_rcvlist_eff_proc_open,
496 .read = seq_read,
497 .llseek = seq_lseek,
498 .release = single_release,
499};
500
459/* 501/*
460 * proc utility functions 502 * proc utility functions
461 */ 503 */
@@ -495,8 +537,8 @@ void can_init_proc(void)
495 &can_rcvlist_proc_fops, (void *)RX_FIL); 537 &can_rcvlist_proc_fops, (void *)RX_FIL);
496 pde_rcvlist_inv = proc_create_data(CAN_PROC_RCVLIST_INV, 0644, can_dir, 538 pde_rcvlist_inv = proc_create_data(CAN_PROC_RCVLIST_INV, 0644, can_dir,
497 &can_rcvlist_proc_fops, (void *)RX_INV); 539 &can_rcvlist_proc_fops, (void *)RX_INV);
498 pde_rcvlist_eff = proc_create_data(CAN_PROC_RCVLIST_EFF, 0644, can_dir, 540 pde_rcvlist_eff = proc_create(CAN_PROC_RCVLIST_EFF, 0644, can_dir,
499 &can_rcvlist_proc_fops, (void *)RX_EFF); 541 &can_rcvlist_eff_proc_fops);
500 pde_rcvlist_sff = proc_create(CAN_PROC_RCVLIST_SFF, 0644, can_dir, 542 pde_rcvlist_sff = proc_create(CAN_PROC_RCVLIST_SFF, 0644, can_dir,
501 &can_rcvlist_sff_proc_fops); 543 &can_rcvlist_sff_proc_fops);
502} 544}