Skip to content

Commit

Permalink
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
Browse files Browse the repository at this point in the history
Pablo Neira Ayuso says:

====================
Netfilter/IPVS updates for net-next

The following patchset contains Netfilter updates for net-next:

1) Support for rejecting packets from the prerouting chain, from
   Laura Garcia Liebana.

2) Remove useless assignment in pipapo, from Stefano Brivio.

3) On demand hook registration in IPVS, from Julian Anastasov.

4) Expire IPVS connection from process context to not overload
   timers, also from Julian.

5) Fallback to conntrack TCP tracker to handle connection reuse
   in IPVS, from Julian Anastasov.

6) Several patches to support for chain bindings.

7) Expose enum nft_chain_flags through UAPI.

8) Reject unsupported chain flags from the netlink control plane.
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
David S. Miller committed Jul 8, 2020
2 parents 3d07ae5 + c1f79a2 commit e80a07b
Show file tree
Hide file tree
Showing 12 changed files with 428 additions and 89 deletions.
15 changes: 9 additions & 6 deletions include/net/ip_vs.h
Original file line number Diff line number Diff line change
Expand Up @@ -874,6 +874,7 @@ struct netns_ipvs {
struct ip_vs_stats tot_stats; /* Statistics & est. */

int num_services; /* no of virtual services */
int num_services6; /* IPv6 virtual services */

/* Trash for destinations */
struct list_head dest_trash;
Expand Down Expand Up @@ -960,6 +961,7 @@ struct netns_ipvs {
* are not supported when synchronization is enabled.
*/
unsigned int mixed_address_family_dests;
unsigned int hooks_afmask; /* &1=AF_INET, &2=AF_INET6 */
};

#define DEFAULT_SYNC_THRESHOLD 3
Expand Down Expand Up @@ -1624,18 +1626,16 @@ static inline void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp)
}
#endif /* CONFIG_IP_VS_NFCT */

/* Really using conntrack? */
static inline bool ip_vs_conn_uses_conntrack(struct ip_vs_conn *cp,
struct sk_buff *skb)
/* Using old conntrack that can not be redirected to another real server? */
static inline bool ip_vs_conn_uses_old_conntrack(struct ip_vs_conn *cp,
struct sk_buff *skb)
{
#ifdef CONFIG_IP_VS_NFCT
enum ip_conntrack_info ctinfo;
struct nf_conn *ct;

if (!(cp->flags & IP_VS_CONN_F_NFCT))
return false;
ct = nf_ct_get(skb, &ctinfo);
if (ct)
if (ct && nf_ct_is_confirmed(ct))
return true;
#endif
return false;
Expand Down Expand Up @@ -1670,6 +1670,9 @@ static inline void ip_vs_unregister_conntrack(struct ip_vs_service *svc)
#endif
}

int ip_vs_register_hooks(struct netns_ipvs *ipvs, unsigned int af);
void ip_vs_unregister_hooks(struct netns_ipvs *ipvs, unsigned int af);

static inline int
ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
{
Expand Down
23 changes: 16 additions & 7 deletions include/net/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -899,6 +899,8 @@ static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule)
return (void *)&rule->data[rule->dlen];
}

void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule);

static inline void nft_set_elem_update_expr(const struct nft_set_ext *ext,
struct nft_regs *regs,
const struct nft_pktinfo *pkt)
Expand All @@ -921,11 +923,6 @@ static inline void nft_set_elem_update_expr(const struct nft_set_ext *ext,
(expr) != (last); \
(expr) = nft_expr_next(expr))

enum nft_chain_flags {
NFT_BASE_CHAIN = 0x1,
NFT_CHAIN_HW_OFFLOAD = 0x2,
};

#define NFT_CHAIN_POLICY_UNSET U8_MAX

/**
Expand All @@ -949,7 +946,8 @@ struct nft_chain {
struct nft_table *table;
u64 handle;
u32 use;
u8 flags:6,
u8 flags:5,
bound:1,
genmask:2;
char *name;

Expand Down Expand Up @@ -994,6 +992,14 @@ int nft_chain_validate_dependency(const struct nft_chain *chain,
int nft_chain_validate_hooks(const struct nft_chain *chain,
unsigned int hook_flags);

static inline bool nft_chain_is_bound(struct nft_chain *chain)
{
return (chain->flags & NFT_CHAIN_BINDING) && chain->bound;
}

void nft_chain_del(struct nft_chain *chain);
void nf_tables_chain_destroy(struct nft_ctx *ctx);

struct nft_stats {
u64 bytes;
u64 pkts;
Expand Down Expand Up @@ -1036,7 +1042,7 @@ static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chai

static inline bool nft_is_base_chain(const struct nft_chain *chain)
{
return chain->flags & NFT_BASE_CHAIN;
return chain->flags & NFT_CHAIN_BASE;
}

int __nft_release_basechain(struct nft_ctx *ctx);
Expand Down Expand Up @@ -1433,6 +1439,7 @@ struct nft_trans_chain {
char *name;
struct nft_stats __percpu *stats;
u8 policy;
u32 chain_id;
};

#define nft_trans_chain_update(trans) \
Expand All @@ -1443,6 +1450,8 @@ struct nft_trans_chain {
(((struct nft_trans_chain *)trans->data)->stats)
#define nft_trans_chain_policy(trans) \
(((struct nft_trans_chain *)trans->data)->policy)
#define nft_trans_chain_id(trans) \
(((struct nft_trans_chain *)trans->data)->chain_id)

struct nft_trans_table {
bool update;
Expand Down
14 changes: 14 additions & 0 deletions include/uapi/linux/netfilter/nf_tables.h
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,15 @@ enum nft_table_attributes {
};
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)

enum nft_chain_flags {
NFT_CHAIN_BASE = (1 << 0),
NFT_CHAIN_HW_OFFLOAD = (1 << 1),
NFT_CHAIN_BINDING = (1 << 2),
};
#define NFT_CHAIN_FLAGS (NFT_CHAIN_BASE | \
NFT_CHAIN_HW_OFFLOAD | \
NFT_CHAIN_BINDING)

/**
* enum nft_chain_attributes - nf_tables chain netlink attributes
*
Expand All @@ -196,6 +205,7 @@ enum nft_table_attributes {
* @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING)
* @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes)
* @NFTA_CHAIN_FLAGS: chain flags
* @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32)
*/
enum nft_chain_attributes {
NFTA_CHAIN_UNSPEC,
Expand All @@ -209,6 +219,7 @@ enum nft_chain_attributes {
NFTA_CHAIN_COUNTERS,
NFTA_CHAIN_PAD,
NFTA_CHAIN_FLAGS,
NFTA_CHAIN_ID,
__NFTA_CHAIN_MAX
};
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
Expand Down Expand Up @@ -238,6 +249,7 @@ enum nft_rule_attributes {
NFTA_RULE_PAD,
NFTA_RULE_ID,
NFTA_RULE_POSITION_ID,
NFTA_RULE_CHAIN_ID,
__NFTA_RULE_MAX
};
#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
Expand Down Expand Up @@ -468,11 +480,13 @@ enum nft_data_attributes {
*
* @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts)
* @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING)
* @NFTA_VERDICT_CHAIN_ID: jump target chain ID (NLA_U32)
*/
enum nft_verdict_attributes {
NFTA_VERDICT_UNSPEC,
NFTA_VERDICT_CODE,
NFTA_VERDICT_CHAIN,
NFTA_VERDICT_CHAIN_ID,
__NFTA_VERDICT_MAX
};
#define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1)
Expand Down
21 changes: 21 additions & 0 deletions net/ipv4/netfilter/nf_reject_ipv4.c
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,21 @@ void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
}
EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put);

static int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
{
struct dst_entry *dst = NULL;
struct flowi fl;

memset(&fl, 0, sizeof(struct flowi));
fl.u.ip4.daddr = ip_hdr(skb_in)->saddr;
nf_ip_route(dev_net(skb_in->dev), &dst, &fl, false);
if (!dst)
return -1;

skb_dst_set(skb_in, dst);
return 0;
}

/* Send RST reply */
void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
{
Expand All @@ -109,6 +124,9 @@ void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
if (!oth)
return;

if (hook == NF_INET_PRE_ROUTING && nf_reject_fill_skb_dst(oldskb))
return;

if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
return;

Expand Down Expand Up @@ -175,6 +193,9 @@ void nf_send_unreach(struct sk_buff *skb_in, int code, int hook)
if (iph->frag_off & htons(IP_OFFSET))
return;

if (hook == NF_INET_PRE_ROUTING && nf_reject_fill_skb_dst(skb_in))
return;

if (skb_csum_unnecessary(skb_in) || !nf_reject_verify_csum(proto)) {
icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
return;
Expand Down
26 changes: 26 additions & 0 deletions net/ipv6/netfilter/nf_reject_ipv6.c
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,21 @@ void nf_reject_ip6_tcphdr_put(struct sk_buff *nskb,
}
EXPORT_SYMBOL_GPL(nf_reject_ip6_tcphdr_put);

static int nf_reject6_fill_skb_dst(struct sk_buff *skb_in)
{
struct dst_entry *dst = NULL;
struct flowi fl;

memset(&fl, 0, sizeof(struct flowi));
fl.u.ip6.daddr = ipv6_hdr(skb_in)->saddr;
nf_ip6_route(dev_net(skb_in->dev), &dst, &fl, false);
if (!dst)
return -1;

skb_dst_set(skb_in, dst);
return 0;
}

void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
{
struct net_device *br_indev __maybe_unused;
Expand Down Expand Up @@ -154,6 +169,14 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
fl6.daddr = oip6h->saddr;
fl6.fl6_sport = otcph->dest;
fl6.fl6_dport = otcph->source;

if (hook == NF_INET_PRE_ROUTING) {
nf_ip6_route(net, &dst, flowi6_to_flowi(&fl6), false);
if (!dst)
return;
skb_dst_set(oldskb, dst);
}

fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev);
fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark);
security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
Expand Down Expand Up @@ -245,6 +268,9 @@ void nf_send_unreach6(struct net *net, struct sk_buff *skb_in,
if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL)
skb_in->dev = net->loopback_dev;

if (hooknum == NF_INET_PRE_ROUTING && nf_reject6_fill_skb_dst(skb_in))
return;

icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0);
}
EXPORT_SYMBOL_GPL(nf_send_unreach6);
Expand Down
53 changes: 38 additions & 15 deletions net/netfilter/ipvs/ip_vs_conn.c
Original file line number Diff line number Diff line change
Expand Up @@ -807,6 +807,31 @@ static void ip_vs_conn_rcu_free(struct rcu_head *head)
kmem_cache_free(ip_vs_conn_cachep, cp);
}

/* Try to delete connection while not holding reference */
static void ip_vs_conn_del(struct ip_vs_conn *cp)
{
if (del_timer(&cp->timer)) {
/* Drop cp->control chain too */
if (cp->control)
cp->timeout = 0;
ip_vs_conn_expire(&cp->timer);
}
}

/* Try to delete connection while holding reference */
static void ip_vs_conn_del_put(struct ip_vs_conn *cp)
{
if (del_timer(&cp->timer)) {
/* Drop cp->control chain too */
if (cp->control)
cp->timeout = 0;
__ip_vs_conn_put(cp);
ip_vs_conn_expire(&cp->timer);
} else {
__ip_vs_conn_put(cp);
}
}

static void ip_vs_conn_expire(struct timer_list *t)
{
struct ip_vs_conn *cp = from_timer(cp, t, timer);
Expand All @@ -827,14 +852,17 @@ static void ip_vs_conn_expire(struct timer_list *t)

/* does anybody control me? */
if (ct) {
bool has_ref = !cp->timeout && __ip_vs_conn_get(ct);

ip_vs_control_del(cp);
/* Drop CTL or non-assured TPL if not used anymore */
if (!cp->timeout && !atomic_read(&ct->n_control) &&
if (has_ref && !atomic_read(&ct->n_control) &&
(!(ct->flags & IP_VS_CONN_F_TEMPLATE) ||
!(ct->state & IP_VS_CTPL_S_ASSURED))) {
IP_VS_DBG(4, "drop controlling connection\n");
ct->timeout = 0;
ip_vs_conn_expire_now(ct);
ip_vs_conn_del_put(ct);
} else if (has_ref) {
__ip_vs_conn_put(ct);
}
}

Expand Down Expand Up @@ -1317,8 +1345,7 @@ void ip_vs_random_dropentry(struct netns_ipvs *ipvs)

drop:
IP_VS_DBG(4, "drop connection\n");
cp->timeout = 0;
ip_vs_conn_expire_now(cp);
ip_vs_conn_del(cp);
}
cond_resched_rcu();
}
Expand All @@ -1341,19 +1368,15 @@ static void ip_vs_conn_flush(struct netns_ipvs *ipvs)
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
if (cp->ipvs != ipvs)
continue;
/* As timers are expired in LIFO order, restart
* the timer of controlling connection first, so
* that it is expired after us.
*/
if (atomic_read(&cp->n_control))
continue;
cp_c = cp->control;
/* cp->control is valid only with reference to cp */
if (cp_c && __ip_vs_conn_get(cp)) {
IP_VS_DBG(4, "del connection\n");
ip_vs_conn_del(cp);
if (cp_c && !atomic_read(&cp_c->n_control)) {
IP_VS_DBG(4, "del controlling connection\n");
ip_vs_conn_expire_now(cp_c);
__ip_vs_conn_put(cp);
ip_vs_conn_del(cp_c);
}
IP_VS_DBG(4, "del connection\n");
ip_vs_conn_expire_now(cp);
}
cond_resched_rcu();
}
Expand Down
Loading

0 comments on commit e80a07b

Please sign in to comment.