Commit 1a01a075 authored by David S. Miller's avatar David S. Miller
Browse files


Pablo Neira Ayuso says:

====================
Netfilter updates for net-next

This is v2 including deadlock fix in conntrack ecache rework
reported by Jakub Kicinski.

The following patchset contains Netfilter updates for net-next,
mostly updates to conntrack from Florian Westphal.

1) Add a dedicated list for conntrack event redelivery.

2) Include event redelivery list in conntrack dumps of dying type.

3) Remove per-cpu dying list for event redelivery, not used anymore.

4) Add netns .pre_exit to cttimeout to zap timeout objects before
   synchronize_rcu() call.

5) Remove nf_ct_unconfirmed_destroy.

6) Add generation id for conntrack extensions for conntrack
   timeout and helpers.

7) Detach timeout policy from conntrack on cttimeout module removal.

8) Remove __nf_ct_unconfirmed_destroy.

9) Remove unconfirmed list.

10) Remove unconditional local_bh_disable in init_conntrack().

11) Consolidate conntrack iterator nf_ct_iterate_cleanup().

12) Detect if ctnetlink listeners exist to short-circuit event
    path early.

13) Un-inline nf_ct_ecache_ext_add().

14) Add nf_conntrack_events autodetect ctnetlink listener mode
    and make it default.

15) Add nf_ct_ecache_exist() to check for event cache extension.

16) Extend flowtable reverse route lookup to include source, iif,
    tos and mark, from Sven Auhagen.

17) Do not verify zero checksum UDP packets in nf_reject,
    from Kevin Mitchell.

====================

Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents d9713088 4f9bd530
Loading
Loading
Loading
Loading
+4 −1
Original line number Diff line number Diff line
@@ -34,10 +34,13 @@ nf_conntrack_count - INTEGER (read-only)

nf_conntrack_events - BOOLEAN
	- 0 - disabled
	- not 0 - enabled (default)
	- 1 - enabled
	- 2 - auto (default)

	If this option is enabled, the connection tracking code will
	provide userspace with connection tracking events via ctnetlink.
	The default allocates the extension if a userspace program is
	listening to ctnetlink events.

nf_conntrack_expect_max - INTEGER
	Maximum size of expectation table.  Default value is
+10 −7
Original line number Diff line number Diff line
@@ -45,7 +45,8 @@ union nf_conntrack_expect_proto {

struct nf_conntrack_net_ecache {
	struct delayed_work dwork;
	struct netns_ct *ct_net;
	spinlock_t dying_lock;
	struct hlist_nulls_head dying_list;
};

struct nf_conntrack_net {
@@ -100,7 +101,6 @@ struct nf_conn {
	/* Have we seen traffic both ways yet? (bitset) */
	unsigned long status;

	u16		cpu;
	possible_net_t ct_net;

#if IS_ENABLED(CONFIG_NF_NAT)
@@ -236,13 +236,16 @@ static inline bool nf_ct_kill(struct nf_conn *ct)
	return nf_ct_delete(ct, 0, 0);
}

/* Set all unconfirmed conntrack as dying */
void nf_ct_unconfirmed_destroy(struct net *);
struct nf_ct_iter_data {
	struct net *net;
	void *data;
	u32 portid;
	int report;
};

/* Iterate over all conntracks: if iter returns true, it's deleted. */
void nf_ct_iterate_cleanup_net(struct net *net,
			       int (*iter)(struct nf_conn *i, void *data),
			       void *data, u32 portid, int report);
void nf_ct_iterate_cleanup_net(int (*iter)(struct nf_conn *i, void *data),
			       const struct nf_ct_iter_data *iter_data);

/* also set unconfirmed conntracks as dying. Only use in module exit path. */
void nf_ct_iterate_destroy(int (*iter)(struct nf_conn *i, void *data),
+1 −1
Original line number Diff line number Diff line
@@ -60,7 +60,7 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb)
	if (ct) {
		if (!nf_ct_is_confirmed(ct))
			ret = __nf_conntrack_confirm(skb);
		if (likely(ret == NF_ACCEPT))
		if (ret == NF_ACCEPT && nf_ct_ecache_exist(ct))
			nf_ct_deliver_cached_events(ct);
	}
	return ret;
+16 −37
Original line number Diff line number Diff line
@@ -14,7 +14,6 @@
#include <net/netfilter/nf_conntrack_extend.h>

enum nf_ct_ecache_state {
	NFCT_ECACHE_UNKNOWN,		/* destroy event not sent */
	NFCT_ECACHE_DESTROY_FAIL,	/* tried but failed to send destroy event */
	NFCT_ECACHE_DESTROY_SENT,	/* sent destroy event after failure */
};
@@ -23,7 +22,6 @@ struct nf_conntrack_ecache {
	unsigned long cache;		/* bitops want long */
	u16 ctmask;			/* bitmask of ct events to be delivered */
	u16 expmask;			/* bitmask of expect events to be delivered */
	enum nf_ct_ecache_state state:8;/* ecache state */
	u32 missed;			/* missed events */
	u32 portid;			/* netlink portid of destroyer */
};
@@ -38,28 +36,12 @@ nf_ct_ecache_find(const struct nf_conn *ct)
#endif
}

static inline struct nf_conntrack_ecache *
nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp)
static inline bool nf_ct_ecache_exist(const struct nf_conn *ct)
{
#ifdef CONFIG_NF_CONNTRACK_EVENTS
	struct net *net = nf_ct_net(ct);
	struct nf_conntrack_ecache *e;

	if (!ctmask && !expmask && net->ct.sysctl_events) {
		ctmask = ~0;
		expmask = ~0;
	}
	if (!ctmask && !expmask)
		return NULL;

	e = nf_ct_ext_add(ct, NF_CT_EXT_ECACHE, gfp);
	if (e) {
		e->ctmask  = ctmask;
		e->expmask = expmask;
	}
	return e;
	return nf_ct_ext_exist(ct, NF_CT_EXT_ECACHE);
#else
	return NULL;
	return false;
#endif
}

@@ -91,6 +73,7 @@ void nf_ct_deliver_cached_events(struct nf_conn *ct);
int nf_conntrack_eventmask_report(unsigned int eventmask, struct nf_conn *ct,
				  u32 portid, int report);

bool nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp);
#else

static inline void nf_ct_deliver_cached_events(const struct nf_conn *ct)
@@ -105,6 +88,10 @@ static inline int nf_conntrack_eventmask_report(unsigned int eventmask,
	return 0;
}

static inline bool nf_ct_ecache_ext_add(struct nf_conn *ct, u16 ctmask, u16 expmask, gfp_t gfp)
{
	return false;
}
#endif

static inline void
@@ -130,30 +117,20 @@ nf_conntrack_event_report(enum ip_conntrack_events event, struct nf_conn *ct,
			  u32 portid, int report)
{
#ifdef CONFIG_NF_CONNTRACK_EVENTS
	const struct net *net = nf_ct_net(ct);

	if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
		return 0;

	if (nf_ct_ecache_exist(ct))
		return nf_conntrack_eventmask_report(1 << event, ct, portid, report);
#else
	return 0;
#endif
	return 0;
}

static inline int
nf_conntrack_event(enum ip_conntrack_events event, struct nf_conn *ct)
{
#ifdef CONFIG_NF_CONNTRACK_EVENTS
	const struct net *net = nf_ct_net(ct);

	if (!rcu_access_pointer(net->ct.nf_conntrack_event_cb))
		return 0;

	if (nf_ct_ecache_exist(ct))
		return nf_conntrack_eventmask_report(1 << event, ct, 0, 0);
#else
	return 0;
#endif
	return 0;
}

#ifdef CONFIG_NF_CONNTRACK_EVENTS
@@ -166,6 +143,8 @@ void nf_conntrack_ecache_work(struct net *net, enum nf_ct_ecache_state state);
void nf_conntrack_ecache_pernet_init(struct net *net);
void nf_conntrack_ecache_pernet_fini(struct net *net);

struct nf_conntrack_net_ecache *nf_conn_pernet_ecache(const struct net *net);

static inline bool nf_conntrack_ecache_dwork_pending(const struct net *net)
{
	return net->ct.ecache_dwork_pending;
+16 −15
Original line number Diff line number Diff line
@@ -34,21 +34,11 @@ enum nf_ct_ext_id {
	NF_CT_EXT_NUM,
};

#define NF_CT_EXT_HELPER_TYPE struct nf_conn_help
#define NF_CT_EXT_NAT_TYPE struct nf_conn_nat
#define NF_CT_EXT_SEQADJ_TYPE struct nf_conn_seqadj
#define NF_CT_EXT_ACCT_TYPE struct nf_conn_acct
#define NF_CT_EXT_ECACHE_TYPE struct nf_conntrack_ecache
#define NF_CT_EXT_TSTAMP_TYPE struct nf_conn_tstamp
#define NF_CT_EXT_TIMEOUT_TYPE struct nf_conn_timeout
#define NF_CT_EXT_LABELS_TYPE struct nf_conn_labels
#define NF_CT_EXT_SYNPROXY_TYPE struct nf_conn_synproxy
#define NF_CT_EXT_ACT_CT_TYPE struct nf_conn_act_ct_ext

/* Extensions: optional stuff which isn't permanently in struct. */
struct nf_ct_ext {
	u8 offset[NF_CT_EXT_NUM];
	u8 len;
	unsigned int gen_id;
	char data[] __aligned(8);
};

@@ -62,17 +52,28 @@ static inline bool nf_ct_ext_exist(const struct nf_conn *ct, u8 id)
	return (ct->ext && __nf_ct_ext_exist(ct->ext, id));
}

static inline void *__nf_ct_ext_find(const struct nf_conn *ct, u8 id)
void *__nf_ct_ext_find(const struct nf_ct_ext *ext, u8 id);

static inline void *nf_ct_ext_find(const struct nf_conn *ct, u8 id)
{
	if (!nf_ct_ext_exist(ct, id))
	struct nf_ct_ext *ext = ct->ext;

	if (!ext || !__nf_ct_ext_exist(ext, id))
		return NULL;

	if (unlikely(ext->gen_id))
		return __nf_ct_ext_find(ext, id);

	return (void *)ct->ext + ct->ext->offset[id];
}
#define nf_ct_ext_find(ext, id)	\
	((id##_TYPE *)__nf_ct_ext_find((ext), (id)))

/* Add this type, returns pointer to data or NULL. */
void *nf_ct_ext_add(struct nf_conn *ct, enum nf_ct_ext_id id, gfp_t gfp);

/* ext genid.  if ext->id != ext_genid, extensions cannot be used
 * anymore unless conntrack has CONFIRMED bit set.
 */
extern atomic_t nf_conntrack_ext_genid;
void nf_ct_ext_bump_genid(void);

#endif /* _NF_CONNTRACK_EXTEND_H */
Loading