Skip to content

Commit 12a169e

Browse files
herbertxdavem330
authored andcommitted
ipsec: Put dumpers on the dump list
Herbert Xu came up with the idea and the original patch to make xfrm_state dump list contain also dumpers: As it is we go to extraordinary lengths to ensure that states don't go away while dumpers go to sleep. It's much easier if we just put the dumpers themselves on the list since they can't go away while they're going. I've also changed the order of addition on new states to prevent a never-ending dump. Timo Teräs improved the patch to apply cleanly to latest tree, modified iteration code to be more readable by using a common struct for entries in the list, implemented the same idea for xfrm_policy dumping and moved the af_key specific "last" entry caching to af_key. Signed-off-by: Herbert Xu <[email protected]> Signed-off-by: Timo Teras <[email protected]> Signed-off-by: David S. Miller <[email protected]>
1 parent b262e60 commit 12a169e

File tree

6 files changed

+159
-175
lines changed

6 files changed

+159
-175
lines changed

include/linux/netlink.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -220,7 +220,7 @@ struct netlink_callback
220220
int (*dump)(struct sk_buff * skb, struct netlink_callback *cb);
221221
int (*done)(struct netlink_callback *cb);
222222
int family;
223-
long args[7];
223+
long args[6];
224224
};
225225

226226
struct netlink_notify

include/net/xfrm.h

Lines changed: 28 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -117,12 +117,21 @@ extern struct mutex xfrm_cfg_mutex;
117117
metrics. Plus, it will be made via sk->sk_dst_cache. Solved.
118118
*/
119119

120+
struct xfrm_state_walk {
121+
struct list_head all;
122+
u8 state;
123+
union {
124+
u8 dying;
125+
u8 proto;
126+
};
127+
u32 seq;
128+
};
129+
120130
/* Full description of state of transformer. */
121131
struct xfrm_state
122132
{
123-
struct list_head all;
124133
union {
125-
struct list_head gclist;
134+
struct hlist_node gclist;
126135
struct hlist_node bydst;
127136
};
128137
struct hlist_node bysrc;
@@ -136,12 +145,8 @@ struct xfrm_state
136145

137146
u32 genid;
138147

139-
/* Key manger bits */
140-
struct {
141-
u8 state;
142-
u8 dying;
143-
u32 seq;
144-
} km;
148+
/* Key manager bits */
149+
struct xfrm_state_walk km;
145150

146151
/* Parameters of this state. */
147152
struct {
@@ -449,10 +454,20 @@ struct xfrm_tmpl
449454

450455
#define XFRM_MAX_DEPTH 6
451456

457+
struct xfrm_policy_walk_entry {
458+
struct list_head all;
459+
u8 dead;
460+
};
461+
462+
struct xfrm_policy_walk {
463+
struct xfrm_policy_walk_entry walk;
464+
u8 type;
465+
u32 seq;
466+
};
467+
452468
struct xfrm_policy
453469
{
454470
struct xfrm_policy *next;
455-
struct list_head bytype;
456471
struct hlist_node bydst;
457472
struct hlist_node byidx;
458473

@@ -467,13 +482,12 @@ struct xfrm_policy
467482
struct xfrm_lifetime_cfg lft;
468483
struct xfrm_lifetime_cur curlft;
469484
struct dst_entry *bundles;
470-
u16 family;
485+
struct xfrm_policy_walk_entry walk;
471486
u8 type;
472487
u8 action;
473488
u8 flags;
474-
u8 dead;
475489
u8 xfrm_nr;
476-
/* XXX 1 byte hole, try to pack */
490+
u16 family;
477491
struct xfrm_sec_ctx *security;
478492
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
479493
};
@@ -1245,20 +1259,6 @@ struct xfrm6_tunnel {
12451259
int priority;
12461260
};
12471261

1248-
struct xfrm_state_walk {
1249-
struct list_head list;
1250-
unsigned long genid;
1251-
struct xfrm_state *state;
1252-
int count;
1253-
u8 proto;
1254-
};
1255-
1256-
struct xfrm_policy_walk {
1257-
struct xfrm_policy *policy;
1258-
int count;
1259-
u8 type, cur_type;
1260-
};
1261-
12621262
extern void xfrm_init(void);
12631263
extern void xfrm4_init(void);
12641264
extern void xfrm_state_init(void);
@@ -1410,24 +1410,10 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)
14101410

14111411
struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);
14121412

1413-
static inline void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
1414-
{
1415-
walk->cur_type = XFRM_POLICY_TYPE_MAIN;
1416-
walk->type = type;
1417-
walk->policy = NULL;
1418-
walk->count = 0;
1419-
}
1420-
1421-
static inline void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
1422-
{
1423-
if (walk->policy != NULL) {
1424-
xfrm_pol_put(walk->policy);
1425-
walk->policy = NULL;
1426-
}
1427-
}
1428-
1413+
extern void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type);
14291414
extern int xfrm_policy_walk(struct xfrm_policy_walk *walk,
14301415
int (*func)(struct xfrm_policy *, int, int, void*), void *);
1416+
extern void xfrm_policy_walk_done(struct xfrm_policy_walk *walk);
14311417
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
14321418
struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
14331419
struct xfrm_selector *sel,

net/key/af_key.c

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,7 @@ struct pfkey_sock {
5858
struct xfrm_policy_walk policy;
5959
struct xfrm_state_walk state;
6060
} u;
61+
struct sk_buff *skb;
6162
} dump;
6263
};
6364

@@ -76,6 +77,10 @@ static int pfkey_can_dump(struct sock *sk)
7677
static void pfkey_terminate_dump(struct pfkey_sock *pfk)
7778
{
7879
if (pfk->dump.dump) {
80+
if (pfk->dump.skb) {
81+
kfree_skb(pfk->dump.skb);
82+
pfk->dump.skb = NULL;
83+
}
7984
pfk->dump.done(pfk);
8085
pfk->dump.dump = NULL;
8186
pfk->dump.done = NULL;
@@ -308,12 +313,25 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
308313

309314
static int pfkey_do_dump(struct pfkey_sock *pfk)
310315
{
316+
struct sadb_msg *hdr;
311317
int rc;
312318

313319
rc = pfk->dump.dump(pfk);
314320
if (rc == -ENOBUFS)
315321
return 0;
316322

323+
if (pfk->dump.skb) {
324+
if (!pfkey_can_dump(&pfk->sk))
325+
return 0;
326+
327+
hdr = (struct sadb_msg *) pfk->dump.skb->data;
328+
hdr->sadb_msg_seq = 0;
329+
hdr->sadb_msg_errno = rc;
330+
pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
331+
&pfk->sk);
332+
pfk->dump.skb = NULL;
333+
}
334+
317335
pfkey_terminate_dump(pfk);
318336
return rc;
319337
}
@@ -1744,9 +1762,14 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr)
17441762
out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
17451763
out_hdr->sadb_msg_errno = 0;
17461764
out_hdr->sadb_msg_reserved = 0;
1747-
out_hdr->sadb_msg_seq = count;
1765+
out_hdr->sadb_msg_seq = count + 1;
17481766
out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
1749-
pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk);
1767+
1768+
if (pfk->dump.skb)
1769+
pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
1770+
&pfk->sk);
1771+
pfk->dump.skb = out_skb;
1772+
17501773
return 0;
17511774
}
17521775

@@ -2245,7 +2268,7 @@ static int pfkey_spdadd(struct sock *sk, struct sk_buff *skb, struct sadb_msg *h
22452268
return 0;
22462269

22472270
out:
2248-
xp->dead = 1;
2271+
xp->walk.dead = 1;
22492272
xfrm_policy_destroy(xp);
22502273
return err;
22512274
}
@@ -2583,9 +2606,14 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
25832606
out_hdr->sadb_msg_type = SADB_X_SPDDUMP;
25842607
out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
25852608
out_hdr->sadb_msg_errno = 0;
2586-
out_hdr->sadb_msg_seq = count;
2609+
out_hdr->sadb_msg_seq = count + 1;
25872610
out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
2588-
pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk);
2611+
2612+
if (pfk->dump.skb)
2613+
pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
2614+
&pfk->sk);
2615+
pfk->dump.skb = out_skb;
2616+
25892617
return 0;
25902618
}
25912619

0 commit comments

Comments
 (0)