Skip to content

Commit e80a07b

Browse files
committed
Merge git://git.kernel.org/pub/scm/linux/kernel/git/pablo/nf-next
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 <[email protected]>
2 parents 3d07ae5 + c1f79a2 commit e80a07b

File tree

12 files changed

+428
-89
lines changed

12 files changed

+428
-89
lines changed

include/net/ip_vs.h

Lines changed: 9 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -874,6 +874,7 @@ struct netns_ipvs {
874874
struct ip_vs_stats tot_stats; /* Statistics & est. */
875875

876876
int num_services; /* no of virtual services */
877+
int num_services6; /* IPv6 virtual services */
877878

878879
/* Trash for destinations */
879880
struct list_head dest_trash;
@@ -960,6 +961,7 @@ struct netns_ipvs {
960961
* are not supported when synchronization is enabled.
961962
*/
962963
unsigned int mixed_address_family_dests;
964+
unsigned int hooks_afmask; /* &1=AF_INET, &2=AF_INET6 */
963965
};
964966

965967
#define DEFAULT_SYNC_THRESHOLD 3
@@ -1624,18 +1626,16 @@ static inline void ip_vs_conn_drop_conntrack(struct ip_vs_conn *cp)
16241626
}
16251627
#endif /* CONFIG_IP_VS_NFCT */
16261628

1627-
/* Really using conntrack? */
1628-
static inline bool ip_vs_conn_uses_conntrack(struct ip_vs_conn *cp,
1629-
struct sk_buff *skb)
1629+
/* Using old conntrack that can not be redirected to another real server? */
1630+
static inline bool ip_vs_conn_uses_old_conntrack(struct ip_vs_conn *cp,
1631+
struct sk_buff *skb)
16301632
{
16311633
#ifdef CONFIG_IP_VS_NFCT
16321634
enum ip_conntrack_info ctinfo;
16331635
struct nf_conn *ct;
16341636

1635-
if (!(cp->flags & IP_VS_CONN_F_NFCT))
1636-
return false;
16371637
ct = nf_ct_get(skb, &ctinfo);
1638-
if (ct)
1638+
if (ct && nf_ct_is_confirmed(ct))
16391639
return true;
16401640
#endif
16411641
return false;
@@ -1670,6 +1670,9 @@ static inline void ip_vs_unregister_conntrack(struct ip_vs_service *svc)
16701670
#endif
16711671
}
16721672

1673+
int ip_vs_register_hooks(struct netns_ipvs *ipvs, unsigned int af);
1674+
void ip_vs_unregister_hooks(struct netns_ipvs *ipvs, unsigned int af);
1675+
16731676
static inline int
16741677
ip_vs_dest_conn_overhead(struct ip_vs_dest *dest)
16751678
{

include/net/netfilter/nf_tables.h

Lines changed: 16 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -899,6 +899,8 @@ static inline struct nft_userdata *nft_userdata(const struct nft_rule *rule)
899899
return (void *)&rule->data[rule->dlen];
900900
}
901901

902+
void nf_tables_rule_release(const struct nft_ctx *ctx, struct nft_rule *rule);
903+
902904
static inline void nft_set_elem_update_expr(const struct nft_set_ext *ext,
903905
struct nft_regs *regs,
904906
const struct nft_pktinfo *pkt)
@@ -921,11 +923,6 @@ static inline void nft_set_elem_update_expr(const struct nft_set_ext *ext,
921923
(expr) != (last); \
922924
(expr) = nft_expr_next(expr))
923925

924-
enum nft_chain_flags {
925-
NFT_BASE_CHAIN = 0x1,
926-
NFT_CHAIN_HW_OFFLOAD = 0x2,
927-
};
928-
929926
#define NFT_CHAIN_POLICY_UNSET U8_MAX
930927

931928
/**
@@ -949,7 +946,8 @@ struct nft_chain {
949946
struct nft_table *table;
950947
u64 handle;
951948
u32 use;
952-
u8 flags:6,
949+
u8 flags:5,
950+
bound:1,
953951
genmask:2;
954952
char *name;
955953

@@ -994,6 +992,14 @@ int nft_chain_validate_dependency(const struct nft_chain *chain,
994992
int nft_chain_validate_hooks(const struct nft_chain *chain,
995993
unsigned int hook_flags);
996994

995+
static inline bool nft_chain_is_bound(struct nft_chain *chain)
996+
{
997+
return (chain->flags & NFT_CHAIN_BINDING) && chain->bound;
998+
}
999+
1000+
void nft_chain_del(struct nft_chain *chain);
1001+
void nf_tables_chain_destroy(struct nft_ctx *ctx);
1002+
9971003
struct nft_stats {
9981004
u64 bytes;
9991005
u64 pkts;
@@ -1036,7 +1042,7 @@ static inline struct nft_base_chain *nft_base_chain(const struct nft_chain *chai
10361042

10371043
static inline bool nft_is_base_chain(const struct nft_chain *chain)
10381044
{
1039-
return chain->flags & NFT_BASE_CHAIN;
1045+
return chain->flags & NFT_CHAIN_BASE;
10401046
}
10411047

10421048
int __nft_release_basechain(struct nft_ctx *ctx);
@@ -1433,6 +1439,7 @@ struct nft_trans_chain {
14331439
char *name;
14341440
struct nft_stats __percpu *stats;
14351441
u8 policy;
1442+
u32 chain_id;
14361443
};
14371444

14381445
#define nft_trans_chain_update(trans) \
@@ -1443,6 +1450,8 @@ struct nft_trans_chain {
14431450
(((struct nft_trans_chain *)trans->data)->stats)
14441451
#define nft_trans_chain_policy(trans) \
14451452
(((struct nft_trans_chain *)trans->data)->policy)
1453+
#define nft_trans_chain_id(trans) \
1454+
(((struct nft_trans_chain *)trans->data)->chain_id)
14461455

14471456
struct nft_trans_table {
14481457
bool update;

include/uapi/linux/netfilter/nf_tables.h

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -184,6 +184,15 @@ enum nft_table_attributes {
184184
};
185185
#define NFTA_TABLE_MAX (__NFTA_TABLE_MAX - 1)
186186

187+
enum nft_chain_flags {
188+
NFT_CHAIN_BASE = (1 << 0),
189+
NFT_CHAIN_HW_OFFLOAD = (1 << 1),
190+
NFT_CHAIN_BINDING = (1 << 2),
191+
};
192+
#define NFT_CHAIN_FLAGS (NFT_CHAIN_BASE | \
193+
NFT_CHAIN_HW_OFFLOAD | \
194+
NFT_CHAIN_BINDING)
195+
187196
/**
188197
* enum nft_chain_attributes - nf_tables chain netlink attributes
189198
*
@@ -196,6 +205,7 @@ enum nft_table_attributes {
196205
* @NFTA_CHAIN_TYPE: type name of the string (NLA_NUL_STRING)
197206
* @NFTA_CHAIN_COUNTERS: counter specification of the chain (NLA_NESTED: nft_counter_attributes)
198207
* @NFTA_CHAIN_FLAGS: chain flags
208+
* @NFTA_CHAIN_ID: uniquely identifies a chain in a transaction (NLA_U32)
199209
*/
200210
enum nft_chain_attributes {
201211
NFTA_CHAIN_UNSPEC,
@@ -209,6 +219,7 @@ enum nft_chain_attributes {
209219
NFTA_CHAIN_COUNTERS,
210220
NFTA_CHAIN_PAD,
211221
NFTA_CHAIN_FLAGS,
222+
NFTA_CHAIN_ID,
212223
__NFTA_CHAIN_MAX
213224
};
214225
#define NFTA_CHAIN_MAX (__NFTA_CHAIN_MAX - 1)
@@ -238,6 +249,7 @@ enum nft_rule_attributes {
238249
NFTA_RULE_PAD,
239250
NFTA_RULE_ID,
240251
NFTA_RULE_POSITION_ID,
252+
NFTA_RULE_CHAIN_ID,
241253
__NFTA_RULE_MAX
242254
};
243255
#define NFTA_RULE_MAX (__NFTA_RULE_MAX - 1)
@@ -468,11 +480,13 @@ enum nft_data_attributes {
468480
*
469481
* @NFTA_VERDICT_CODE: nf_tables verdict (NLA_U32: enum nft_verdicts)
470482
* @NFTA_VERDICT_CHAIN: jump target chain name (NLA_STRING)
483+
* @NFTA_VERDICT_CHAIN_ID: jump target chain ID (NLA_U32)
471484
*/
472485
enum nft_verdict_attributes {
473486
NFTA_VERDICT_UNSPEC,
474487
NFTA_VERDICT_CODE,
475488
NFTA_VERDICT_CHAIN,
489+
NFTA_VERDICT_CHAIN_ID,
476490
__NFTA_VERDICT_MAX
477491
};
478492
#define NFTA_VERDICT_MAX (__NFTA_VERDICT_MAX - 1)

net/ipv4/netfilter/nf_reject_ipv4.c

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,21 @@ void nf_reject_ip_tcphdr_put(struct sk_buff *nskb, const struct sk_buff *oldskb,
9696
}
9797
EXPORT_SYMBOL_GPL(nf_reject_ip_tcphdr_put);
9898

99+
static int nf_reject_fill_skb_dst(struct sk_buff *skb_in)
100+
{
101+
struct dst_entry *dst = NULL;
102+
struct flowi fl;
103+
104+
memset(&fl, 0, sizeof(struct flowi));
105+
fl.u.ip4.daddr = ip_hdr(skb_in)->saddr;
106+
nf_ip_route(dev_net(skb_in->dev), &dst, &fl, false);
107+
if (!dst)
108+
return -1;
109+
110+
skb_dst_set(skb_in, dst);
111+
return 0;
112+
}
113+
99114
/* Send RST reply */
100115
void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
101116
{
@@ -109,6 +124,9 @@ void nf_send_reset(struct net *net, struct sk_buff *oldskb, int hook)
109124
if (!oth)
110125
return;
111126

127+
if (hook == NF_INET_PRE_ROUTING && nf_reject_fill_skb_dst(oldskb))
128+
return;
129+
112130
if (skb_rtable(oldskb)->rt_flags & (RTCF_BROADCAST | RTCF_MULTICAST))
113131
return;
114132

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

196+
if (hook == NF_INET_PRE_ROUTING && nf_reject_fill_skb_dst(skb_in))
197+
return;
198+
178199
if (skb_csum_unnecessary(skb_in) || !nf_reject_verify_csum(proto)) {
179200
icmp_send(skb_in, ICMP_DEST_UNREACH, code, 0);
180201
return;

net/ipv6/netfilter/nf_reject_ipv6.c

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,21 @@ void nf_reject_ip6_tcphdr_put(struct sk_buff *nskb,
126126
}
127127
EXPORT_SYMBOL_GPL(nf_reject_ip6_tcphdr_put);
128128

129+
static int nf_reject6_fill_skb_dst(struct sk_buff *skb_in)
130+
{
131+
struct dst_entry *dst = NULL;
132+
struct flowi fl;
133+
134+
memset(&fl, 0, sizeof(struct flowi));
135+
fl.u.ip6.daddr = ipv6_hdr(skb_in)->saddr;
136+
nf_ip6_route(dev_net(skb_in->dev), &dst, &fl, false);
137+
if (!dst)
138+
return -1;
139+
140+
skb_dst_set(skb_in, dst);
141+
return 0;
142+
}
143+
129144
void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
130145
{
131146
struct net_device *br_indev __maybe_unused;
@@ -154,6 +169,14 @@ void nf_send_reset6(struct net *net, struct sk_buff *oldskb, int hook)
154169
fl6.daddr = oip6h->saddr;
155170
fl6.fl6_sport = otcph->dest;
156171
fl6.fl6_dport = otcph->source;
172+
173+
if (hook == NF_INET_PRE_ROUTING) {
174+
nf_ip6_route(net, &dst, flowi6_to_flowi(&fl6), false);
175+
if (!dst)
176+
return;
177+
skb_dst_set(oldskb, dst);
178+
}
179+
157180
fl6.flowi6_oif = l3mdev_master_ifindex(skb_dst(oldskb)->dev);
158181
fl6.flowi6_mark = IP6_REPLY_MARK(net, oldskb->mark);
159182
security_skb_classify_flow(oldskb, flowi6_to_flowi(&fl6));
@@ -245,6 +268,9 @@ void nf_send_unreach6(struct net *net, struct sk_buff *skb_in,
245268
if (hooknum == NF_INET_LOCAL_OUT && skb_in->dev == NULL)
246269
skb_in->dev = net->loopback_dev;
247270

271+
if (hooknum == NF_INET_PRE_ROUTING && nf_reject6_fill_skb_dst(skb_in))
272+
return;
273+
248274
icmpv6_send(skb_in, ICMPV6_DEST_UNREACH, code, 0);
249275
}
250276
EXPORT_SYMBOL_GPL(nf_send_unreach6);

net/netfilter/ipvs/ip_vs_conn.c

Lines changed: 38 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -807,6 +807,31 @@ static void ip_vs_conn_rcu_free(struct rcu_head *head)
807807
kmem_cache_free(ip_vs_conn_cachep, cp);
808808
}
809809

810+
/* Try to delete connection while not holding reference */
811+
static void ip_vs_conn_del(struct ip_vs_conn *cp)
812+
{
813+
if (del_timer(&cp->timer)) {
814+
/* Drop cp->control chain too */
815+
if (cp->control)
816+
cp->timeout = 0;
817+
ip_vs_conn_expire(&cp->timer);
818+
}
819+
}
820+
821+
/* Try to delete connection while holding reference */
822+
static void ip_vs_conn_del_put(struct ip_vs_conn *cp)
823+
{
824+
if (del_timer(&cp->timer)) {
825+
/* Drop cp->control chain too */
826+
if (cp->control)
827+
cp->timeout = 0;
828+
__ip_vs_conn_put(cp);
829+
ip_vs_conn_expire(&cp->timer);
830+
} else {
831+
__ip_vs_conn_put(cp);
832+
}
833+
}
834+
810835
static void ip_vs_conn_expire(struct timer_list *t)
811836
{
812837
struct ip_vs_conn *cp = from_timer(cp, t, timer);
@@ -827,14 +852,17 @@ static void ip_vs_conn_expire(struct timer_list *t)
827852

828853
/* does anybody control me? */
829854
if (ct) {
855+
bool has_ref = !cp->timeout && __ip_vs_conn_get(ct);
856+
830857
ip_vs_control_del(cp);
831858
/* Drop CTL or non-assured TPL if not used anymore */
832-
if (!cp->timeout && !atomic_read(&ct->n_control) &&
859+
if (has_ref && !atomic_read(&ct->n_control) &&
833860
(!(ct->flags & IP_VS_CONN_F_TEMPLATE) ||
834861
!(ct->state & IP_VS_CTPL_S_ASSURED))) {
835862
IP_VS_DBG(4, "drop controlling connection\n");
836-
ct->timeout = 0;
837-
ip_vs_conn_expire_now(ct);
863+
ip_vs_conn_del_put(ct);
864+
} else if (has_ref) {
865+
__ip_vs_conn_put(ct);
838866
}
839867
}
840868

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

13181346
drop:
13191347
IP_VS_DBG(4, "drop connection\n");
1320-
cp->timeout = 0;
1321-
ip_vs_conn_expire_now(cp);
1348+
ip_vs_conn_del(cp);
13221349
}
13231350
cond_resched_rcu();
13241351
}
@@ -1341,19 +1368,15 @@ static void ip_vs_conn_flush(struct netns_ipvs *ipvs)
13411368
hlist_for_each_entry_rcu(cp, &ip_vs_conn_tab[idx], c_list) {
13421369
if (cp->ipvs != ipvs)
13431370
continue;
1344-
/* As timers are expired in LIFO order, restart
1345-
* the timer of controlling connection first, so
1346-
* that it is expired after us.
1347-
*/
1371+
if (atomic_read(&cp->n_control))
1372+
continue;
13481373
cp_c = cp->control;
1349-
/* cp->control is valid only with reference to cp */
1350-
if (cp_c && __ip_vs_conn_get(cp)) {
1374+
IP_VS_DBG(4, "del connection\n");
1375+
ip_vs_conn_del(cp);
1376+
if (cp_c && !atomic_read(&cp_c->n_control)) {
13511377
IP_VS_DBG(4, "del controlling connection\n");
1352-
ip_vs_conn_expire_now(cp_c);
1353-
__ip_vs_conn_put(cp);
1378+
ip_vs_conn_del(cp_c);
13541379
}
1355-
IP_VS_DBG(4, "del connection\n");
1356-
ip_vs_conn_expire_now(cp);
13571380
}
13581381
cond_resched_rcu();
13591382
}

0 commit comments

Comments
 (0)