Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge tag 'ipsec-next-2024-09-10' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next

Steffen Klassert says:

====================
pull request (net-next): ipsec-next 2024-09-10

1) Remove an unneeded WARN_ON on packet offload.
From Patrisious Haddad.

2) Add a copy from skb_seq_state to buffer function.
This is needed for the upcomming IPTFS patchset.
From Christian Hopps.

3) Spelling fix in xfrm.h.
From Simon Horman.

4) Speed up xfrm policy insertions.
From Florian Westphal.

5) Add and revert a patch to support xfrm interfaces
for packet offload. This patch was just half cooked.

6) Extend usage of the new xfrm_policy_is_dead_or_sk helper.
From Florian Westphal.

7) Update comments on sdb and xfrm_policy.
From Florian Westphal.

8) Fix a null pointer dereference in the new policy insertion
code From Florian Westphal.

9) Fix an uninitialized variable in the new policy insertion
code. From Nathan Chancellor.

* tag 'ipsec-next-2024-09-10' of git://git.kernel.org/pub/scm/linux/kernel/git/klassert/ipsec-next:
xfrm: policy: Restore dir assignments in xfrm_hash_rebuild()
xfrm: policy: fix null dereference
Revert "xfrm: add SA information to the offloaded packet"
xfrm: minor update to sdb and xfrm_policy comments
xfrm: policy: use recently added helper in more places
xfrm: add SA information to the offloaded packet
xfrm: policy: remove remaining use of inexact list
xfrm: switch migrate to xfrm_policy_lookup_bytype
xfrm: policy: don't iterate inexact policies twice at insert time
selftests: add xfrm policy insertion speed test script
xfrm: Correct spelling in xfrm.h
net: add copy from skb_seq_state to buffer function
xfrm: Remove documentation WARN_ON to limit return values for offloaded SA
====================

Link: https://patch.msgid.link/20240910065507.2436394-1-steffen.klassert@secunet.com
Signed-off-by: Jakub Kicinski <kuba@kernel.org>

+259 -137
+1
include/linux/skbuff.h
··· 1433 1433 unsigned int skb_seq_read(unsigned int consumed, const u8 **data, 1434 1434 struct skb_seq_state *st); 1435 1435 void skb_abort_seq_read(struct skb_seq_state *st); 1436 + int skb_copy_seq_read(struct skb_seq_state *st, int offset, void *to, int len); 1436 1437 1437 1438 unsigned int skb_find_text(struct sk_buff *skb, unsigned int from, 1438 1439 unsigned int to, struct ts_config *config);
+37 -8
include/net/xfrm.h
··· 67 67 - instance of a transformer, struct xfrm_state (=SA) 68 68 - template to clone xfrm_state, struct xfrm_tmpl 69 69 70 - SPD is plain linear list of xfrm_policy rules, ordered by priority. 70 + SPD is organized as hash table (for policies that meet minimum address prefix 71 + length setting, net->xfrm.policy_hthresh). Other policies are stored in 72 + lists, sorted into rbtree ordered by destination and source address networks. 73 + See net/xfrm/xfrm_policy.c for details. 74 + 71 75 (To be compatible with existing pfkeyv2 implementations, 72 76 many rules with priority of 0x7fffffff are allowed to exist and 73 77 such rules are ordered in an unpredictable way, thanks to bsd folks.) 74 - 75 - Lookup is plain linear search until the first match with selector. 76 78 77 79 If "action" is "block", then we prohibit the flow, otherwise: 78 80 if "xfrms_nr" is zero, the flow passes untransformed. Otherwise, 79 81 policy entry has list of up to XFRM_MAX_DEPTH transformations, 80 82 described by templates xfrm_tmpl. Each template is resolved 81 83 to a complete xfrm_state (see below) and we pack bundle of transformations 82 - to a dst_entry returned to requestor. 84 + to a dst_entry returned to requester. 83 85 84 86 dst -. xfrm .-> xfrm_state #1 85 87 |---. child .-> dst -. xfrm .-> xfrm_state #2 86 88 |---. child .-> dst -. xfrm .-> xfrm_state #3 87 89 |---. child .-> NULL 88 - 89 - Bundles are cached at xrfm_policy struct (field ->bundles). 90 90 91 91 92 92 Resolution of xrfm_tmpl ··· 526 526 unsigned long timeout; 527 527 }; 528 528 529 + /** 530 + * struct xfrm_policy - xfrm policy 531 + * @xp_net: network namespace the policy lives in 532 + * @bydst: hlist node for SPD hash table or rbtree list 533 + * @byidx: hlist node for index hash table 534 + * @lock: serialize changes to policy structure members 535 + * @refcnt: reference count, freed once it reaches 0 536 + * @pos: kernel internal tie-breaker to determine age of policy 537 + * @timer: timer 538 + * @genid: generation, used to invalidate old policies 539 + * @priority: priority, set by userspace 540 + * @index: policy index (autogenerated) 541 + * @if_id: virtual xfrm interface id 542 + * @mark: packet mark 543 + * @selector: selector 544 + * @lft: liftime configuration data 545 + * @curlft: liftime state 546 + * @walk: list head on pernet policy list 547 + * @polq: queue to hold packets while aqcuire operaion in progress 548 + * @bydst_reinsert: policy tree node needs to be merged 549 + * @type: XFRM_POLICY_TYPE_MAIN or _SUB 550 + * @action: XFRM_POLICY_ALLOW or _BLOCK 551 + * @flags: XFRM_POLICY_LOCALOK, XFRM_POLICY_ICMP 552 + * @xfrm_nr: number of used templates in @xfrm_vec 553 + * @family: protocol family 554 + * @security: SELinux security label 555 + * @xfrm_vec: array of templates to resolve state 556 + * @rcu: rcu head, used to defer memory release 557 + * @xdo: hardware offload state 558 + */ 529 559 struct xfrm_policy { 530 560 possible_net_t xp_net; 531 561 struct hlist_node bydst; ··· 585 555 u16 family; 586 556 struct xfrm_sec_ctx *security; 587 557 struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH]; 588 - struct hlist_node bydst_inexact_list; 589 558 struct rcu_head rcu; 590 559 591 560 struct xfrm_dev_offload xdo; ··· 1045 1016 1046 1017 struct xfrm_if_parms { 1047 1018 int link; /* ifindex of underlying L2 interface */ 1048 - u32 if_id; /* interface identifyer */ 1019 + u32 if_id; /* interface identifier */ 1049 1020 bool collect_md; 1050 1021 }; 1051 1022
+35
net/core/skbuff.c
··· 4411 4411 } 4412 4412 EXPORT_SYMBOL(skb_abort_seq_read); 4413 4413 4414 + /** 4415 + * skb_copy_seq_read() - copy from a skb_seq_state to a buffer 4416 + * @st: source skb_seq_state 4417 + * @offset: offset in source 4418 + * @to: destination buffer 4419 + * @len: number of bytes to copy 4420 + * 4421 + * Copy @len bytes from @offset bytes into the source @st to the destination 4422 + * buffer @to. `offset` should increase (or be unchanged) with each subsequent 4423 + * call to this function. If offset needs to decrease from the previous use `st` 4424 + * should be reset first. 4425 + * 4426 + * Return: 0 on success or -EINVAL if the copy ended early 4427 + */ 4428 + int skb_copy_seq_read(struct skb_seq_state *st, int offset, void *to, int len) 4429 + { 4430 + const u8 *data; 4431 + u32 sqlen; 4432 + 4433 + for (;;) { 4434 + sqlen = skb_seq_read(offset, &data, st); 4435 + if (sqlen == 0) 4436 + return -EINVAL; 4437 + if (sqlen >= len) { 4438 + memcpy(to, data, len); 4439 + return 0; 4440 + } 4441 + memcpy(to, data, sqlen); 4442 + to += sqlen; 4443 + offset += sqlen; 4444 + len -= sqlen; 4445 + } 4446 + } 4447 + EXPORT_SYMBOL(skb_copy_seq_read); 4448 + 4414 4449 #define TS_SKB_CB(state) ((struct skb_seq_state *) &((state)->cb)) 4415 4450 4416 4451 static unsigned int skb_ts_get_next_block(unsigned int offset, const u8 **text,
+1 -5
net/xfrm/xfrm_device.c
··· 328 328 /* User explicitly requested packet offload mode and configured 329 329 * policy in addition to the XFRM state. So be civil to users, 330 330 * and return an error instead of taking fallback path. 331 - * 332 - * This WARN_ON() can be seen as a documentation for driver 333 - * authors to do not return -EOPNOTSUPP in packet offload mode. 334 331 */ 335 - WARN_ON(err == -EOPNOTSUPP && is_packet_offload); 336 - if (err != -EOPNOTSUPP || is_packet_offload) { 332 + if ((err != -EOPNOTSUPP && !is_packet_offload) || is_packet_offload) { 337 333 NL_SET_ERR_MSG_WEAK(extack, "Device failed to offload this state"); 338 334 return err; 339 335 }
+101 -123
net/xfrm/xfrm_policy.c
··· 110 110 * 4. saddr:any list from saddr tree 111 111 * 112 112 * This result set then needs to be searched for the policy with 113 - * the lowest priority. If two results have same prio, youngest one wins. 113 + * the lowest priority. If two candidates have the same priority, the 114 + * struct xfrm_policy pos member with the lower number is used. 115 + * 116 + * This replicates previous single-list-search algorithm which would 117 + * return first matching policy in the (ordered-by-priority) list. 114 118 */ 115 119 116 120 struct xfrm_pol_inexact_key { ··· 201 197 static struct xfrm_policy * 202 198 xfrm_policy_insert_list(struct hlist_head *chain, struct xfrm_policy *policy, 203 199 bool excl); 204 - static void xfrm_policy_insert_inexact_list(struct hlist_head *chain, 205 - struct xfrm_policy *policy); 206 200 207 201 static bool 208 202 xfrm_policy_find_inexact_candidates(struct xfrm_pol_inexact_candidates *cand, ··· 413 411 if (policy) { 414 412 write_pnet(&policy->xp_net, net); 415 413 INIT_LIST_HEAD(&policy->walk.all); 416 - INIT_HLIST_NODE(&policy->bydst_inexact_list); 417 414 INIT_HLIST_NODE(&policy->bydst); 418 415 INIT_HLIST_NODE(&policy->byidx); 419 416 rwlock_init(&policy->lock); ··· 1230 1229 return ERR_PTR(-EEXIST); 1231 1230 } 1232 1231 1233 - chain = &net->xfrm.policy_inexact[dir]; 1234 - xfrm_policy_insert_inexact_list(chain, policy); 1235 - 1236 1232 if (delpol) 1237 1233 __xfrm_policy_inexact_prune_bin(bin, false); 1238 1234 1239 1235 return delpol; 1240 1236 } 1241 1237 1238 + static bool xfrm_policy_is_dead_or_sk(const struct xfrm_policy *policy) 1239 + { 1240 + int dir; 1241 + 1242 + if (policy->walk.dead) 1243 + return true; 1244 + 1245 + dir = xfrm_policy_id2dir(policy->index); 1246 + return dir >= XFRM_POLICY_MAX; 1247 + } 1248 + 1242 1249 static void xfrm_hash_rebuild(struct work_struct *work) 1243 1250 { 1244 1251 struct net *net = container_of(work, struct net, 1245 1252 xfrm.policy_hthresh.work); 1246 - unsigned int hmask; 1247 1253 struct xfrm_policy *pol; 1248 1254 struct xfrm_policy *policy; 1249 1255 struct hlist_head *chain; 1250 - struct hlist_head *odst; 1251 1256 struct hlist_node *newpos; 1252 - int i; 1253 1257 int dir; 1254 1258 unsigned seq; 1255 1259 u8 lbits4, rbits4, lbits6, rbits6; ··· 1281 1275 struct xfrm_pol_inexact_bin *bin; 1282 1276 u8 dbits, sbits; 1283 1277 1284 - if (policy->walk.dead) 1278 + if (xfrm_policy_is_dead_or_sk(policy)) 1285 1279 continue; 1286 1280 1287 1281 dir = xfrm_policy_id2dir(policy->index); 1288 - if (dir >= XFRM_POLICY_MAX) 1289 - continue; 1290 - 1291 1282 if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) { 1292 1283 if (policy->family == AF_INET) { 1293 1284 dbits = rbits4; ··· 1315 1312 goto out_unlock; 1316 1313 } 1317 1314 1318 - /* reset the bydst and inexact table in all directions */ 1319 1315 for (dir = 0; dir < XFRM_POLICY_MAX; dir++) { 1320 - struct hlist_node *n; 1321 - 1322 - hlist_for_each_entry_safe(policy, n, 1323 - &net->xfrm.policy_inexact[dir], 1324 - bydst_inexact_list) { 1325 - hlist_del_rcu(&policy->bydst); 1326 - hlist_del_init(&policy->bydst_inexact_list); 1327 - } 1328 - 1329 - hmask = net->xfrm.policy_bydst[dir].hmask; 1330 - odst = net->xfrm.policy_bydst[dir].table; 1331 - for (i = hmask; i >= 0; i--) { 1332 - hlist_for_each_entry_safe(policy, n, odst + i, bydst) 1333 - hlist_del_rcu(&policy->bydst); 1334 - } 1335 1316 if ((dir & XFRM_POLICY_MASK) == XFRM_POLICY_OUT) { 1336 1317 /* dir out => dst = remote, src = local */ 1337 1318 net->xfrm.policy_bydst[dir].dbits4 = rbits4; ··· 1333 1346 1334 1347 /* re-insert all policies by order of creation */ 1335 1348 list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) { 1336 - if (policy->walk.dead) 1349 + if (xfrm_policy_is_dead_or_sk(policy)) 1337 1350 continue; 1338 - dir = xfrm_policy_id2dir(policy->index); 1339 - if (dir >= XFRM_POLICY_MAX) { 1340 - /* skip socket policies */ 1341 - continue; 1342 - } 1351 + 1352 + hlist_del_rcu(&policy->bydst); 1353 + 1343 1354 newpos = NULL; 1355 + dir = xfrm_policy_id2dir(policy->index); 1344 1356 chain = policy_hash_bysel(net, &policy->selector, 1345 1357 policy->family, dir); 1346 1358 ··· 1505 1519 .obj_cmpfn = xfrm_pol_bin_cmp, 1506 1520 .automatic_shrinking = true, 1507 1521 }; 1508 - 1509 - static void xfrm_policy_insert_inexact_list(struct hlist_head *chain, 1510 - struct xfrm_policy *policy) 1511 - { 1512 - struct xfrm_policy *pol, *delpol = NULL; 1513 - struct hlist_node *newpos = NULL; 1514 - int i = 0; 1515 - 1516 - hlist_for_each_entry(pol, chain, bydst_inexact_list) { 1517 - if (pol->type == policy->type && 1518 - pol->if_id == policy->if_id && 1519 - !selector_cmp(&pol->selector, &policy->selector) && 1520 - xfrm_policy_mark_match(&policy->mark, pol) && 1521 - xfrm_sec_ctx_match(pol->security, policy->security) && 1522 - !WARN_ON(delpol)) { 1523 - delpol = pol; 1524 - if (policy->priority > pol->priority) 1525 - continue; 1526 - } else if (policy->priority >= pol->priority) { 1527 - newpos = &pol->bydst_inexact_list; 1528 - continue; 1529 - } 1530 - if (delpol) 1531 - break; 1532 - } 1533 - 1534 - if (newpos && policy->xdo.type != XFRM_DEV_OFFLOAD_PACKET) 1535 - hlist_add_behind_rcu(&policy->bydst_inexact_list, newpos); 1536 - else 1537 - hlist_add_head_rcu(&policy->bydst_inexact_list, chain); 1538 - 1539 - hlist_for_each_entry(pol, chain, bydst_inexact_list) { 1540 - pol->pos = i; 1541 - i++; 1542 - } 1543 - } 1544 1522 1545 1523 static struct xfrm_policy *xfrm_policy_insert_list(struct hlist_head *chain, 1546 1524 struct xfrm_policy *policy, ··· 2245 2295 return pol; 2246 2296 } 2247 2297 2298 + static u32 xfrm_gen_pos_slow(struct net *net) 2299 + { 2300 + struct xfrm_policy *policy; 2301 + u32 i = 0; 2302 + 2303 + /* oldest entry is last in list */ 2304 + list_for_each_entry_reverse(policy, &net->xfrm.policy_all, walk.all) { 2305 + if (!xfrm_policy_is_dead_or_sk(policy)) 2306 + policy->pos = ++i; 2307 + } 2308 + 2309 + return i; 2310 + } 2311 + 2312 + static u32 xfrm_gen_pos(struct net *net) 2313 + { 2314 + const struct xfrm_policy *policy; 2315 + u32 i = 0; 2316 + 2317 + /* most recently added policy is at the head of the list */ 2318 + list_for_each_entry(policy, &net->xfrm.policy_all, walk.all) { 2319 + if (xfrm_policy_is_dead_or_sk(policy)) 2320 + continue; 2321 + 2322 + if (policy->pos == UINT_MAX) 2323 + return xfrm_gen_pos_slow(net); 2324 + 2325 + i = policy->pos + 1; 2326 + break; 2327 + } 2328 + 2329 + return i; 2330 + } 2331 + 2248 2332 static void __xfrm_policy_link(struct xfrm_policy *pol, int dir) 2249 2333 { 2250 2334 struct net *net = xp_net(pol); 2335 + 2336 + switch (dir) { 2337 + case XFRM_POLICY_IN: 2338 + case XFRM_POLICY_FWD: 2339 + case XFRM_POLICY_OUT: 2340 + pol->pos = xfrm_gen_pos(net); 2341 + break; 2342 + } 2251 2343 2252 2344 list_add(&pol->walk.all, &net->xfrm.policy_all); 2253 2345 net->xfrm.policy_count[dir]++; ··· 2307 2315 /* Socket policies are not hashed. */ 2308 2316 if (!hlist_unhashed(&pol->bydst)) { 2309 2317 hlist_del_rcu(&pol->bydst); 2310 - hlist_del_init(&pol->bydst_inexact_list); 2311 2318 hlist_del(&pol->byidx); 2312 2319 } 2313 2320 ··· 4429 4438 #endif 4430 4439 4431 4440 #ifdef CONFIG_XFRM_MIGRATE 4432 - static bool xfrm_migrate_selector_match(const struct xfrm_selector *sel_cmp, 4433 - const struct xfrm_selector *sel_tgt) 4434 - { 4435 - if (sel_cmp->proto == IPSEC_ULPROTO_ANY) { 4436 - if (sel_tgt->family == sel_cmp->family && 4437 - xfrm_addr_equal(&sel_tgt->daddr, &sel_cmp->daddr, 4438 - sel_cmp->family) && 4439 - xfrm_addr_equal(&sel_tgt->saddr, &sel_cmp->saddr, 4440 - sel_cmp->family) && 4441 - sel_tgt->prefixlen_d == sel_cmp->prefixlen_d && 4442 - sel_tgt->prefixlen_s == sel_cmp->prefixlen_s) { 4443 - return true; 4444 - } 4445 - } else { 4446 - if (memcmp(sel_tgt, sel_cmp, sizeof(*sel_tgt)) == 0) { 4447 - return true; 4448 - } 4449 - } 4450 - return false; 4451 - } 4452 - 4453 4441 static struct xfrm_policy *xfrm_migrate_policy_find(const struct xfrm_selector *sel, 4454 4442 u8 dir, u8 type, struct net *net, u32 if_id) 4455 4443 { 4456 - struct xfrm_policy *pol, *ret = NULL; 4457 - struct hlist_head *chain; 4458 - u32 priority = ~0U; 4444 + struct xfrm_policy *pol; 4445 + struct flowi fl; 4459 4446 4460 - spin_lock_bh(&net->xfrm.xfrm_policy_lock); 4461 - chain = policy_hash_direct(net, &sel->daddr, &sel->saddr, sel->family, dir); 4462 - hlist_for_each_entry(pol, chain, bydst) { 4463 - if ((if_id == 0 || pol->if_id == if_id) && 4464 - xfrm_migrate_selector_match(sel, &pol->selector) && 4465 - pol->type == type) { 4466 - ret = pol; 4467 - priority = ret->priority; 4447 + memset(&fl, 0, sizeof(fl)); 4448 + 4449 + fl.flowi_proto = sel->proto; 4450 + 4451 + switch (sel->family) { 4452 + case AF_INET: 4453 + fl.u.ip4.saddr = sel->saddr.a4; 4454 + fl.u.ip4.daddr = sel->daddr.a4; 4455 + if (sel->proto == IPSEC_ULPROTO_ANY) 4468 4456 break; 4469 - } 4457 + fl.u.flowi4_oif = sel->ifindex; 4458 + fl.u.ip4.fl4_sport = sel->sport; 4459 + fl.u.ip4.fl4_dport = sel->dport; 4460 + break; 4461 + case AF_INET6: 4462 + fl.u.ip6.saddr = sel->saddr.in6; 4463 + fl.u.ip6.daddr = sel->daddr.in6; 4464 + if (sel->proto == IPSEC_ULPROTO_ANY) 4465 + break; 4466 + fl.u.flowi6_oif = sel->ifindex; 4467 + fl.u.ip6.fl4_sport = sel->sport; 4468 + fl.u.ip6.fl4_dport = sel->dport; 4469 + break; 4470 + default: 4471 + return ERR_PTR(-EAFNOSUPPORT); 4470 4472 } 4471 - chain = &net->xfrm.policy_inexact[dir]; 4472 - hlist_for_each_entry(pol, chain, bydst_inexact_list) { 4473 - if ((pol->priority >= priority) && ret) 4474 - break; 4475 4473 4476 - if ((if_id == 0 || pol->if_id == if_id) && 4477 - xfrm_migrate_selector_match(sel, &pol->selector) && 4478 - pol->type == type) { 4479 - ret = pol; 4480 - break; 4481 - } 4482 - } 4474 + rcu_read_lock(); 4483 4475 4484 - xfrm_pol_hold(ret); 4476 + pol = xfrm_policy_lookup_bytype(net, type, &fl, sel->family, dir, if_id); 4477 + if (IS_ERR_OR_NULL(pol)) 4478 + goto out_unlock; 4485 4479 4486 - spin_unlock_bh(&net->xfrm.xfrm_policy_lock); 4487 - 4488 - return ret; 4480 + if (!xfrm_pol_hold_rcu(pol)) 4481 + pol = NULL; 4482 + out_unlock: 4483 + rcu_read_unlock(); 4484 + return pol; 4489 4485 } 4490 4486 4491 4487 static int migrate_tmpl_match(const struct xfrm_migrate *m, const struct xfrm_tmpl *t) ··· 4609 4631 4610 4632 /* Stage 1 - find policy */ 4611 4633 pol = xfrm_migrate_policy_find(sel, dir, type, net, if_id); 4612 - if (!pol) { 4634 + if (IS_ERR_OR_NULL(pol)) { 4613 4635 NL_SET_ERR_MSG(extack, "Target policy not found"); 4614 - err = -ENOENT; 4636 + err = IS_ERR(pol) ? PTR_ERR(pol) : -ENOENT; 4615 4637 goto out; 4616 4638 } 4617 4639
+1 -1
tools/testing/selftests/net/Makefile
··· 56 56 TEST_PROGS += rps_default_mask.sh 57 57 TEST_PROGS += big_tcp.sh 58 58 TEST_PROGS += netns-sysctl.sh 59 - TEST_PROGS_EXTENDED := toeplitz_client.sh toeplitz.sh 59 + TEST_PROGS_EXTENDED := toeplitz_client.sh toeplitz.sh xfrm_policy_add_speed.sh 60 60 TEST_GEN_FILES = socket nettest 61 61 TEST_GEN_FILES += psock_fanout psock_tpacket msg_zerocopy reuseport_addr_any 62 62 TEST_GEN_FILES += tcp_mmap tcp_inq psock_snd txring_overwrite
+83
tools/testing/selftests/net/xfrm_policy_add_speed.sh
··· 1 + #!/bin/bash 2 + # SPDX-License-Identifier: GPL-2.0 3 + # 4 + source lib.sh 5 + 6 + timeout=4m 7 + ret=0 8 + tmp=$(mktemp) 9 + cleanup() { 10 + cleanup_all_ns 11 + rm -f "$tmp" 12 + } 13 + 14 + trap cleanup EXIT 15 + 16 + maxpolicies=100000 17 + [ "$KSFT_MACHINE_SLOW" = "yes" ] && maxpolicies=10000 18 + 19 + do_dummies4() { 20 + local dir="$1" 21 + local max="$2" 22 + 23 + local policies 24 + local pfx 25 + pfx=30 26 + policies=0 27 + 28 + ip netns exec "$ns" ip xfrm policy flush 29 + 30 + for i in $(seq 1 100);do 31 + local s 32 + local d 33 + for j in $(seq 1 255);do 34 + s=$((i+0)) 35 + d=$((i+100)) 36 + 37 + for a in $(seq 1 8 255); do 38 + policies=$((policies+1)) 39 + [ "$policies" -gt "$max" ] && return 40 + echo xfrm policy add src 10.$s.$j.0/30 dst 10.$d.$j.$a/$pfx dir $dir action block 41 + done 42 + for a in $(seq 1 8 255); do 43 + policies=$((policies+1)) 44 + [ "$policies" -gt "$max" ] && return 45 + echo xfrm policy add src 10.$s.$j.$a/30 dst 10.$d.$j.0/$pfx dir $dir action block 46 + done 47 + done 48 + done 49 + } 50 + 51 + setup_ns ns 52 + 53 + do_bench() 54 + { 55 + local max="$1" 56 + 57 + start=$(date +%s%3N) 58 + do_dummies4 "out" "$max" > "$tmp" 59 + if ! timeout "$timeout" ip netns exec "$ns" ip -batch "$tmp";then 60 + echo "WARNING: policy insertion cancelled after $timeout" 61 + ret=1 62 + fi 63 + stop=$(date +%s%3N) 64 + 65 + result=$((stop-start)) 66 + 67 + policies=$(wc -l < "$tmp") 68 + printf "Inserted %-06s policies in $result ms\n" $policies 69 + 70 + have=$(ip netns exec "$ns" ip xfrm policy show | grep "action block" | wc -l) 71 + if [ "$have" -ne "$policies" ]; then 72 + echo "WARNING: mismatch, have $have policies, expected $policies" 73 + ret=1 74 + fi 75 + } 76 + 77 + p=100 78 + while [ $p -le "$maxpolicies" ]; do 79 + do_bench "$p" 80 + p="${p}0" 81 + done 82 + 83 + exit $ret