Commit 45c70029 authored by Oliver Hartkopp's avatar Oliver Hartkopp Committed by Marc Kleine-Budde

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: default avatarOliver Hartkopp <socketcan@hartkopp.net>
Signed-off-by: default avatarMarc Kleine-Budde <mkl@pengutronix.de>
parent e3d3917f
...@@ -337,6 +337,29 @@ static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev) ...@@ -337,6 +337,29 @@ static struct dev_rcv_lists *find_dev_rcv_lists(struct net_device *dev)
return (struct dev_rcv_lists *)dev->ml_priv; return (struct dev_rcv_lists *)dev->ml_priv;
} }
/**
* effhash - hash function for 29 bit CAN identifier reduction
* @can_id: 29 bit CAN identifier
*
* Description:
* To reduce the linear traversal in one linked list of _single_ EFF CAN
* frame subscriptions the 29 bit identifier is mapped to 10 bits.
* (see CAN_EFF_RCV_HASH_BITS definition)
*
* Return:
* Hash value from 0x000 - 0x3FF ( enforced by CAN_EFF_RCV_HASH_BITS mask )
*/
static unsigned int effhash(canid_t can_id)
{
unsigned int hash;
hash = can_id;
hash ^= can_id >> CAN_EFF_RCV_HASH_BITS;
hash ^= can_id >> (2 * CAN_EFF_RCV_HASH_BITS);
return hash & ((1 << CAN_EFF_RCV_HASH_BITS) - 1);
}
/** /**
* find_rcv_list - determine optimal filterlist inside device filter struct * find_rcv_list - determine optimal filterlist inside device filter struct
* @can_id: pointer to CAN identifier of a given can_filter * @can_id: pointer to CAN identifier of a given can_filter
...@@ -400,10 +423,8 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask, ...@@ -400,10 +423,8 @@ static struct hlist_head *find_rcv_list(canid_t *can_id, canid_t *mask,
!(*can_id & CAN_RTR_FLAG)) { !(*can_id & CAN_RTR_FLAG)) {
if (*can_id & CAN_EFF_FLAG) { if (*can_id & CAN_EFF_FLAG) {
if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS)) { if (*mask == (CAN_EFF_MASK | CAN_EFF_RTR_FLAGS))
/* RFC: a future use-case for hash-tables? */ return &d->rx_eff[effhash(*can_id)];
return &d->rx[RX_EFF];
}
} else { } else {
if (*mask == (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS)) if (*mask == (CAN_SFF_MASK | CAN_EFF_RTR_FLAGS))
return &d->rx_sff[*can_id]; 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,7 +653,7 @@ static int can_rcv_filter(struct dev_rcv_lists *d, struct sk_buff *skb)
return matches; return matches;
if (can_id & CAN_EFF_FLAG) { if (can_id & CAN_EFF_FLAG) {
hlist_for_each_entry_rcu(r, &d->rx[RX_EFF], list) { hlist_for_each_entry_rcu(r, &d->rx_eff[effhash(can_id)], list) {
if (r->can_id == can_id) { if (r->can_id == can_id) {
deliver(skb, r); deliver(skb, r);
matches++; matches++;
......
...@@ -60,13 +60,16 @@ struct receiver { ...@@ -60,13 +60,16 @@ struct receiver {
}; };
#define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS) #define CAN_SFF_RCV_ARRAY_SZ (1 << CAN_SFF_ID_BITS)
#define CAN_EFF_RCV_HASH_BITS 10
#define CAN_EFF_RCV_ARRAY_SZ (1 << CAN_EFF_RCV_HASH_BITS)
enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_EFF, RX_MAX }; enum { RX_ERR, RX_ALL, RX_FIL, RX_INV, RX_MAX };
/* per device receive filters linked at dev->ml_priv */ /* per device receive filters linked at dev->ml_priv */
struct dev_rcv_lists { struct dev_rcv_lists {
struct hlist_head rx[RX_MAX]; struct hlist_head rx[RX_MAX];
struct hlist_head rx_sff[CAN_SFF_RCV_ARRAY_SZ]; struct hlist_head rx_sff[CAN_SFF_RCV_ARRAY_SZ];
struct hlist_head rx_eff[CAN_EFF_RCV_ARRAY_SZ];
int remove_on_zero_entries; int remove_on_zero_entries;
int entries; int entries;
}; };
......
...@@ -80,7 +80,6 @@ static const char rx_list_name[][8] = { ...@@ -80,7 +80,6 @@ static const char rx_list_name[][8] = {
[RX_ALL] = "rx_all", [RX_ALL] = "rx_all",
[RX_FIL] = "rx_fil", [RX_FIL] = "rx_fil",
[RX_INV] = "rx_inv", [RX_INV] = "rx_inv",
[RX_EFF] = "rx_eff",
}; };
/* /*
...@@ -456,6 +455,49 @@ static const struct file_operations can_rcvlist_sff_proc_fops = { ...@@ -456,6 +455,49 @@ static const struct file_operations can_rcvlist_sff_proc_fops = {
.release = single_release, .release = single_release,
}; };
static int can_rcvlist_eff_proc_show(struct seq_file *m, void *v)
{
struct net_device *dev;
struct dev_rcv_lists *d;
/* RX_EFF */
seq_puts(m, "\nreceive list 'rx_eff':\n");
rcu_read_lock();
/* eff receive list for 'all' CAN devices (dev == NULL) */
d = &can_rx_alldev_list;
can_rcvlist_proc_show_array(m, NULL, d->rx_eff, ARRAY_SIZE(d->rx_eff));
/* eff receive list for registered CAN devices */
for_each_netdev_rcu(&init_net, dev) {
if (dev->type == ARPHRD_CAN && dev->ml_priv) {
d = dev->ml_priv;
can_rcvlist_proc_show_array(m, dev, d->rx_eff,
ARRAY_SIZE(d->rx_eff));
}
}
rcu_read_unlock();
seq_putc(m, '\n');
return 0;
}
static int can_rcvlist_eff_proc_open(struct inode *inode, struct file *file)
{
return single_open(file, can_rcvlist_eff_proc_show, NULL);
}
static const struct file_operations can_rcvlist_eff_proc_fops = {
.owner = THIS_MODULE,
.open = can_rcvlist_eff_proc_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
/* /*
* proc utility functions * proc utility functions
*/ */
...@@ -495,8 +537,8 @@ void can_init_proc(void) ...@@ -495,8 +537,8 @@ void can_init_proc(void)
&can_rcvlist_proc_fops, (void *)RX_FIL); &can_rcvlist_proc_fops, (void *)RX_FIL);
pde_rcvlist_inv = proc_create_data(CAN_PROC_RCVLIST_INV, 0644, can_dir, pde_rcvlist_inv = proc_create_data(CAN_PROC_RCVLIST_INV, 0644, can_dir,
&can_rcvlist_proc_fops, (void *)RX_INV); &can_rcvlist_proc_fops, (void *)RX_INV);
pde_rcvlist_eff = proc_create_data(CAN_PROC_RCVLIST_EFF, 0644, can_dir, pde_rcvlist_eff = proc_create(CAN_PROC_RCVLIST_EFF, 0644, can_dir,
&can_rcvlist_proc_fops, (void *)RX_EFF); &can_rcvlist_eff_proc_fops);
pde_rcvlist_sff = proc_create(CAN_PROC_RCVLIST_SFF, 0644, can_dir, pde_rcvlist_sff = proc_create(CAN_PROC_RCVLIST_SFF, 0644, can_dir,
&can_rcvlist_sff_proc_fops); &can_rcvlist_sff_proc_fops);
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment