Skip to content

Commit 6ac098b

Browse files
Florian Westphalklassert
authored andcommitted
xfrm: policy: add 2nd-level saddr trees for inexact policies
This adds the fourth and final search class, containing policies where both saddr and daddr have prefix lengths (i.e., not wildcards). Inexact policies now end up in one of the following four search classes: 1. "Any:Any" list, containing policies where both saddr and daddr are wildcards or have very coarse prefixes, e.g. 10.0.0.0/8 and the like. 2. "saddr:any" list, containing policies with a fixed saddr/prefixlen, but without destination restrictions. These lists are stored in rbtree nodes; each node contains those policies matching saddr/prefixlen. 3. "Any:daddr" list. Similar to 2), except for policies where only the destinations are specified. 4. "saddr:daddr" lists, containing only those policies that match the given source/destination network. The root of the saddr/daddr nodes gets stored in the nodes of the 'daddr' tree. This diagram illustrates the list classes, and their placement in the lookup hierarchy: xfrm_pol_inexact_bin = hash(dir,type,family,if_id); | +---- root_d: sorted by daddr:prefix | | | xfrm_pol_inexact_node | | | +- root: sorted by saddr/prefix | | | | | xfrm_pol_inexact_node | | | | | + root: unused | | | | | + hhead: saddr:daddr policies | | | +- coarse policies and all any:daddr policies | +---- root_s: sorted by saddr:prefix | | | xfrm_pol_inexact_node | | | + root: unused | | | + hhead: saddr:any policies | +---- coarse policies and all any:any policies lookup for an inexact policy returns pointers to the four relevant list classes, after which each of the lists needs to be searched for the policy with the higher priority. This will only speed up lookups in case we have many policies and a sizeable portion of these have disjunct saddr/daddr addresses. Signed-off-by: Florian Westphal <[email protected]> Acked-by: David S. Miller <[email protected]> Signed-off-by: Steffen Klassert <[email protected]>
1 parent 64a09a7 commit 6ac098b

File tree

1 file changed

+108
-10
lines changed

1 file changed

+108
-10
lines changed

net/xfrm/xfrm_policy.c

Lines changed: 108 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ struct xfrm_pol_inexact_node {
5858
};
5959
u8 prefixlen;
6060

61+
struct rb_root root;
62+
6163
/* the policies matching this node, can be empty list */
6264
struct hlist_head hhead;
6365
};
@@ -69,6 +71,14 @@ struct xfrm_pol_inexact_node {
6971
* | |
7072
* | xfrm_pol_inexact_node
7173
* | |
74+
* | +- root: sorted by saddr/prefix
75+
* | | |
76+
* | | xfrm_pol_inexact_node
77+
* | | |
78+
* | | + root: unused
79+
* | | |
80+
* | | + hhead: saddr:daddr policies
81+
* | |
7282
* | +- coarse policies and all any:daddr policies
7383
* |
7484
* +---- root_s: sorted by saddr:prefix
@@ -81,10 +91,11 @@ struct xfrm_pol_inexact_node {
8191
* |
8292
* +---- coarse policies and all any:any policies
8393
*
84-
* Lookups return three candidate lists:
94+
* Lookups return four candidate lists:
8595
* 1. any:any list from top-level xfrm_pol_inexact_bin
8696
* 2. any:daddr list from daddr tree
87-
* 2. saddr:any list from saddr tree
97+
* 3. saddr:daddr list from 2nd level daddr tree
98+
* 4. saddr:any list from saddr tree
8899
*
89100
* This result set then needs to be searched for the policy with
90101
* the lowest priority. If two results have same prio, youngest one wins.
@@ -116,6 +127,7 @@ struct xfrm_pol_inexact_bin {
116127
};
117128

118129
enum xfrm_pol_inexact_candidate_type {
130+
XFRM_POL_CAND_BOTH,
119131
XFRM_POL_CAND_SADDR,
120132
XFRM_POL_CAND_DADDR,
121133
XFRM_POL_CAND_ANY,
@@ -876,13 +888,82 @@ static void xfrm_policy_inexact_list_reinsert(struct net *net,
876888
}
877889
}
878890

891+
static void xfrm_policy_inexact_node_reinsert(struct net *net,
892+
struct xfrm_pol_inexact_node *n,
893+
struct rb_root *new,
894+
u16 family)
895+
{
896+
struct rb_node **p, *parent = NULL;
897+
struct xfrm_pol_inexact_node *node;
898+
899+
/* we should not have another subtree here */
900+
WARN_ON_ONCE(!RB_EMPTY_ROOT(&n->root));
901+
902+
p = &new->rb_node;
903+
while (*p) {
904+
u8 prefixlen;
905+
int delta;
906+
907+
parent = *p;
908+
node = rb_entry(*p, struct xfrm_pol_inexact_node, node);
909+
910+
prefixlen = min(node->prefixlen, n->prefixlen);
911+
912+
delta = xfrm_policy_addr_delta(&n->addr, &node->addr,
913+
prefixlen, family);
914+
if (delta < 0) {
915+
p = &parent->rb_left;
916+
} else if (delta > 0) {
917+
p = &parent->rb_right;
918+
} else {
919+
struct xfrm_policy *tmp;
920+
921+
hlist_for_each_entry(tmp, &node->hhead, bydst)
922+
tmp->bydst_reinsert = true;
923+
hlist_for_each_entry(tmp, &n->hhead, bydst)
924+
tmp->bydst_reinsert = true;
925+
926+
INIT_HLIST_HEAD(&node->hhead);
927+
xfrm_policy_inexact_list_reinsert(net, node, family);
928+
929+
if (node->prefixlen == n->prefixlen) {
930+
kfree_rcu(n, rcu);
931+
return;
932+
}
933+
934+
rb_erase(*p, new);
935+
kfree_rcu(n, rcu);
936+
n = node;
937+
n->prefixlen = prefixlen;
938+
*p = new->rb_node;
939+
parent = NULL;
940+
}
941+
}
942+
943+
rb_link_node_rcu(&n->node, parent, p);
944+
rb_insert_color(&n->node, new);
945+
}
946+
879947
/* merge nodes v and n */
880948
static void xfrm_policy_inexact_node_merge(struct net *net,
881949
struct xfrm_pol_inexact_node *v,
882950
struct xfrm_pol_inexact_node *n,
883951
u16 family)
884952
{
953+
struct xfrm_pol_inexact_node *node;
885954
struct xfrm_policy *tmp;
955+
struct rb_node *rnode;
956+
957+
/* To-be-merged node v has a subtree.
958+
*
959+
* Dismantle it and insert its nodes to n->root.
960+
*/
961+
while ((rnode = rb_first(&v->root)) != NULL) {
962+
node = rb_entry(rnode, struct xfrm_pol_inexact_node, node);
963+
rb_erase(&node->node, &v->root);
964+
xfrm_policy_inexact_node_reinsert(net, node, &n->root,
965+
family);
966+
}
886967

887968
hlist_for_each_entry(tmp, &v->hhead, bydst)
888969
tmp->bydst_reinsert = true;
@@ -978,9 +1059,10 @@ static void xfrm_policy_inexact_gc_tree(struct rb_root *r, bool rm)
9781059
while (rn) {
9791060
node = rb_entry(rn, struct xfrm_pol_inexact_node, node);
9801061

1062+
xfrm_policy_inexact_gc_tree(&node->root, rm);
9811063
rn = rb_next(rn);
9821064

983-
if (!hlist_empty(&node->hhead)) {
1065+
if (!hlist_empty(&node->hhead) || !RB_EMPTY_ROOT(&node->root)) {
9841066
WARN_ON_ONCE(rm);
9851067
continue;
9861068
}
@@ -1042,12 +1124,6 @@ xfrm_policy_inexact_alloc_chain(struct xfrm_pol_inexact_bin *bin,
10421124
if (xfrm_policy_inexact_insert_use_any_list(policy))
10431125
return &bin->hhead;
10441126

1045-
/* saddr is wildcard */
1046-
if (xfrm_pol_inexact_addr_use_any_list(&policy->selector.saddr,
1047-
policy->family,
1048-
policy->selector.prefixlen_s))
1049-
return &bin->hhead;
1050-
10511127
if (xfrm_pol_inexact_addr_use_any_list(&policy->selector.daddr,
10521128
policy->family,
10531129
policy->selector.prefixlen_d)) {
@@ -1075,6 +1151,23 @@ xfrm_policy_inexact_alloc_chain(struct xfrm_pol_inexact_bin *bin,
10751151
write_seqcount_end(&bin->count);
10761152
if (!n)
10771153
return NULL;
1154+
1155+
/* saddr is wildcard */
1156+
if (xfrm_pol_inexact_addr_use_any_list(&policy->selector.saddr,
1157+
policy->family,
1158+
policy->selector.prefixlen_s))
1159+
return &n->hhead;
1160+
1161+
write_seqcount_begin(&bin->count);
1162+
n = xfrm_policy_inexact_insert_node(net,
1163+
&n->root,
1164+
&policy->selector.saddr,
1165+
policy->family,
1166+
policy->selector.prefixlen_s, dir);
1167+
write_seqcount_end(&bin->count);
1168+
if (!n)
1169+
return NULL;
1170+
10781171
return &n->hhead;
10791172
}
10801173

@@ -1856,8 +1949,13 @@ xfrm_policy_find_inexact_candidates(struct xfrm_pol_inexact_candidates *cand,
18561949

18571950
n = xfrm_policy_lookup_inexact_addr(&b->root_d, &b->count, daddr,
18581951
family);
1859-
if (n)
1952+
if (n) {
18601953
cand->res[XFRM_POL_CAND_DADDR] = &n->hhead;
1954+
n = xfrm_policy_lookup_inexact_addr(&n->root, &b->count, saddr,
1955+
family);
1956+
if (n)
1957+
cand->res[XFRM_POL_CAND_BOTH] = &n->hhead;
1958+
}
18611959

18621960
n = xfrm_policy_lookup_inexact_addr(&b->root_s, &b->count, saddr,
18631961
family);

0 commit comments

Comments
 (0)