|
@@ -344,12 +344,39 @@ static inline unsigned int idx_hash(struct net *net, u32 index)
|
|
|
return __idx_hash(index, net->xfrm.policy_idx_hmask);
|
|
|
}
|
|
|
|
|
|
+/* calculate policy hash thresholds */
|
|
|
+static void __get_hash_thresh(struct net *net,
|
|
|
+ unsigned short family, int dir,
|
|
|
+ u8 *dbits, u8 *sbits)
|
|
|
+{
|
|
|
+ switch (family) {
|
|
|
+ case AF_INET:
|
|
|
+ *dbits = net->xfrm.policy_bydst[dir].dbits4;
|
|
|
+ *sbits = net->xfrm.policy_bydst[dir].sbits4;
|
|
|
+ break;
|
|
|
+
|
|
|
+ case AF_INET6:
|
|
|
+ *dbits = net->xfrm.policy_bydst[dir].dbits6;
|
|
|
+ *sbits = net->xfrm.policy_bydst[dir].sbits6;
|
|
|
+ break;
|
|
|
+
|
|
|
+ default:
|
|
|
+ *dbits = 0;
|
|
|
+ *sbits = 0;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
static struct hlist_head *policy_hash_bysel(struct net *net,
|
|
|
const struct xfrm_selector *sel,
|
|
|
unsigned short family, int dir)
|
|
|
{
|
|
|
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
|
|
|
- unsigned int hash = __sel_hash(sel, family, hmask);
|
|
|
+ unsigned int hash;
|
|
|
+ u8 dbits;
|
|
|
+ u8 sbits;
|
|
|
+
|
|
|
+ __get_hash_thresh(net, family, dir, &dbits, &sbits);
|
|
|
+ hash = __sel_hash(sel, family, hmask, dbits, sbits);
|
|
|
|
|
|
return (hash == hmask + 1 ?
|
|
|
&net->xfrm.policy_inexact[dir] :
|
|
@@ -362,25 +389,35 @@ static struct hlist_head *policy_hash_direct(struct net *net,
|
|
|
unsigned short family, int dir)
|
|
|
{
|
|
|
unsigned int hmask = net->xfrm.policy_bydst[dir].hmask;
|
|
|
- unsigned int hash = __addr_hash(daddr, saddr, family, hmask);
|
|
|
+ unsigned int hash;
|
|
|
+ u8 dbits;
|
|
|
+ u8 sbits;
|
|
|
+
|
|
|
+ __get_hash_thresh(net, family, dir, &dbits, &sbits);
|
|
|
+ hash = __addr_hash(daddr, saddr, family, hmask, dbits, sbits);
|
|
|
|
|
|
return net->xfrm.policy_bydst[dir].table + hash;
|
|
|
}
|
|
|
|
|
|
-static void xfrm_dst_hash_transfer(struct hlist_head *list,
|
|
|
+static void xfrm_dst_hash_transfer(struct net *net,
|
|
|
+ struct hlist_head *list,
|
|
|
struct hlist_head *ndsttable,
|
|
|
- unsigned int nhashmask)
|
|
|
+ unsigned int nhashmask,
|
|
|
+ int dir)
|
|
|
{
|
|
|
struct hlist_node *tmp, *entry0 = NULL;
|
|
|
struct xfrm_policy *pol;
|
|
|
unsigned int h0 = 0;
|
|
|
+ u8 dbits;
|
|
|
+ u8 sbits;
|
|
|
|
|
|
redo:
|
|
|
hlist_for_each_entry_safe(pol, tmp, list, bydst) {
|
|
|
unsigned int h;
|
|
|
|
|
|
+ __get_hash_thresh(net, pol->family, dir, &dbits, &sbits);
|
|
|
h = __addr_hash(&pol->selector.daddr, &pol->selector.saddr,
|
|
|
- pol->family, nhashmask);
|
|
|
+ pol->family, nhashmask, dbits, sbits);
|
|
|
if (!entry0) {
|
|
|
hlist_del(&pol->bydst);
|
|
|
hlist_add_head(&pol->bydst, ndsttable+h);
|
|
@@ -434,7 +471,7 @@ static void xfrm_bydst_resize(struct net *net, int dir)
|
|
|
write_lock_bh(&net->xfrm.xfrm_policy_lock);
|
|
|
|
|
|
for (i = hmask; i >= 0; i--)
|
|
|
- xfrm_dst_hash_transfer(odst + i, ndst, nhashmask);
|
|
|
+ xfrm_dst_hash_transfer(net, odst + i, ndst, nhashmask, dir);
|
|
|
|
|
|
net->xfrm.policy_bydst[dir].table = ndst;
|
|
|
net->xfrm.policy_bydst[dir].hmask = nhashmask;
|
|
@@ -2830,6 +2867,10 @@ static int __net_init xfrm_policy_init(struct net *net)
|
|
|
if (!htab->table)
|
|
|
goto out_bydst;
|
|
|
htab->hmask = hmask;
|
|
|
+ htab->dbits4 = 32;
|
|
|
+ htab->sbits4 = 32;
|
|
|
+ htab->dbits6 = 128;
|
|
|
+ htab->sbits6 = 128;
|
|
|
}
|
|
|
|
|
|
INIT_LIST_HEAD(&net->xfrm.policy_all);
|