Skip to content

Commit

Permalink
ipsec: Put dumpers on the dump list
Browse files Browse the repository at this point in the history
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]>
  • Loading branch information
herbertx authored and davem330 committed Oct 1, 2008
1 parent b262e60 commit 12a169e
Show file tree
Hide file tree
Showing 6 changed files with 159 additions and 175 deletions.
2 changes: 1 addition & 1 deletion include/linux/netlink.h
Original file line number Diff line number Diff line change
Expand Up @@ -220,7 +220,7 @@ struct netlink_callback
int (*dump)(struct sk_buff * skb, struct netlink_callback *cb);
int (*done)(struct netlink_callback *cb);
int family;
long args[7];
long args[6];
};

struct netlink_notify
Expand Down
70 changes: 28 additions & 42 deletions include/net/xfrm.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,12 +117,21 @@ extern struct mutex xfrm_cfg_mutex;
metrics. Plus, it will be made via sk->sk_dst_cache. Solved.
*/

struct xfrm_state_walk {
struct list_head all;
u8 state;
union {
u8 dying;
u8 proto;
};
u32 seq;
};

/* Full description of state of transformer. */
struct xfrm_state
{
struct list_head all;
union {
struct list_head gclist;
struct hlist_node gclist;
struct hlist_node bydst;
};
struct hlist_node bysrc;
Expand All @@ -136,12 +145,8 @@ struct xfrm_state

u32 genid;

/* Key manger bits */
struct {
u8 state;
u8 dying;
u32 seq;
} km;
/* Key manager bits */
struct xfrm_state_walk km;

/* Parameters of this state. */
struct {
Expand Down Expand Up @@ -449,10 +454,20 @@ struct xfrm_tmpl

#define XFRM_MAX_DEPTH 6

struct xfrm_policy_walk_entry {
struct list_head all;
u8 dead;
};

struct xfrm_policy_walk {
struct xfrm_policy_walk_entry walk;
u8 type;
u32 seq;
};

struct xfrm_policy
{
struct xfrm_policy *next;
struct list_head bytype;
struct hlist_node bydst;
struct hlist_node byidx;

Expand All @@ -467,13 +482,12 @@ struct xfrm_policy
struct xfrm_lifetime_cfg lft;
struct xfrm_lifetime_cur curlft;
struct dst_entry *bundles;
u16 family;
struct xfrm_policy_walk_entry walk;
u8 type;
u8 action;
u8 flags;
u8 dead;
u8 xfrm_nr;
/* XXX 1 byte hole, try to pack */
u16 family;
struct xfrm_sec_ctx *security;
struct xfrm_tmpl xfrm_vec[XFRM_MAX_DEPTH];
};
Expand Down Expand Up @@ -1245,20 +1259,6 @@ struct xfrm6_tunnel {
int priority;
};

struct xfrm_state_walk {
struct list_head list;
unsigned long genid;
struct xfrm_state *state;
int count;
u8 proto;
};

struct xfrm_policy_walk {
struct xfrm_policy *policy;
int count;
u8 type, cur_type;
};

extern void xfrm_init(void);
extern void xfrm4_init(void);
extern void xfrm_state_init(void);
Expand Down Expand Up @@ -1410,24 +1410,10 @@ static inline int xfrm4_udp_encap_rcv(struct sock *sk, struct sk_buff *skb)

struct xfrm_policy *xfrm_policy_alloc(gfp_t gfp);

static inline void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type)
{
walk->cur_type = XFRM_POLICY_TYPE_MAIN;
walk->type = type;
walk->policy = NULL;
walk->count = 0;
}

static inline void xfrm_policy_walk_done(struct xfrm_policy_walk *walk)
{
if (walk->policy != NULL) {
xfrm_pol_put(walk->policy);
walk->policy = NULL;
}
}

extern void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type);
extern int xfrm_policy_walk(struct xfrm_policy_walk *walk,
int (*func)(struct xfrm_policy *, int, int, void*), void *);
extern void xfrm_policy_walk_done(struct xfrm_policy_walk *walk);
int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl);
struct xfrm_policy *xfrm_policy_bysel_ctx(u8 type, int dir,
struct xfrm_selector *sel,
Expand Down
38 changes: 33 additions & 5 deletions net/key/af_key.c
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,7 @@ struct pfkey_sock {
struct xfrm_policy_walk policy;
struct xfrm_state_walk state;
} u;
struct sk_buff *skb;
} dump;
};

Expand All @@ -76,6 +77,10 @@ static int pfkey_can_dump(struct sock *sk)
static void pfkey_terminate_dump(struct pfkey_sock *pfk)
{
if (pfk->dump.dump) {
if (pfk->dump.skb) {
kfree_skb(pfk->dump.skb);
pfk->dump.skb = NULL;
}
pfk->dump.done(pfk);
pfk->dump.dump = NULL;
pfk->dump.done = NULL;
Expand Down Expand Up @@ -308,12 +313,25 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,

static int pfkey_do_dump(struct pfkey_sock *pfk)
{
struct sadb_msg *hdr;
int rc;

rc = pfk->dump.dump(pfk);
if (rc == -ENOBUFS)
return 0;

if (pfk->dump.skb) {
if (!pfkey_can_dump(&pfk->sk))
return 0;

hdr = (struct sadb_msg *) pfk->dump.skb->data;
hdr->sadb_msg_seq = 0;
hdr->sadb_msg_errno = rc;
pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
&pfk->sk);
pfk->dump.skb = NULL;
}

pfkey_terminate_dump(pfk);
return rc;
}
Expand Down Expand Up @@ -1744,9 +1762,14 @@ static int dump_sa(struct xfrm_state *x, int count, void *ptr)
out_hdr->sadb_msg_satype = pfkey_proto2satype(x->id.proto);
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_reserved = 0;
out_hdr->sadb_msg_seq = count;
out_hdr->sadb_msg_seq = count + 1;
out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk);

if (pfk->dump.skb)
pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
&pfk->sk);
pfk->dump.skb = out_skb;

return 0;
}

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

out:
xp->dead = 1;
xp->walk.dead = 1;
xfrm_policy_destroy(xp);
return err;
}
Expand Down Expand Up @@ -2583,9 +2606,14 @@ static int dump_sp(struct xfrm_policy *xp, int dir, int count, void *ptr)
out_hdr->sadb_msg_type = SADB_X_SPDDUMP;
out_hdr->sadb_msg_satype = SADB_SATYPE_UNSPEC;
out_hdr->sadb_msg_errno = 0;
out_hdr->sadb_msg_seq = count;
out_hdr->sadb_msg_seq = count + 1;
out_hdr->sadb_msg_pid = pfk->dump.msg_pid;
pfkey_broadcast(out_skb, GFP_ATOMIC, BROADCAST_ONE, &pfk->sk);

if (pfk->dump.skb)
pfkey_broadcast(pfk->dump.skb, GFP_ATOMIC, BROADCAST_ONE,
&pfk->sk);
pfk->dump.skb = out_skb;

return 0;
}

Expand Down
Loading

0 comments on commit 12a169e

Please sign in to comment.