netfilter: nf_defrag_ipv4: Add sysctl to disable per interface

Add a sysctl nf_ipv4_defrag_skip to skip defragmentation per
interface. This is set 0 to preserve existing behavior (always
defrag per interface).

This is useful for pure ipv4 forwarding scenarios (without NAT)
in conjunction with xfrm. It appears that network stack defrags
the packets and then forwards them to xfrm which then encrypts
and then later fragments them on a different boundary compared
to the source.

CRs-Fixed: 2333588
Change-Id: I11956284a9692579274e8626f61cc6432232254c
Signed-off-by: Subash Abhinov Kasiviswanathan <subashab@codeaurora.org>
This commit is contained in:
Subash Abhinov Kasiviswanathan 2017-11-05 17:36:53 -07:00 committed by Gerrit - the friendly Code Review server
parent 46e3ca3632
commit acfb09cac1
7 changed files with 19 additions and 2 deletions

View File

@ -1337,6 +1337,10 @@ igmp_link_local_mcast_reports - BOOLEAN
224.0.0.X range.
Default TRUE
nf_ipv4_defrag_skip - BOOLEAN
Skip defragmentation per interface if set.
Default : 0 (always defrag)
Alexey Kuznetsov.
kuznet@ms2.inr.ac.ru

View File

@ -131,6 +131,8 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev)
#define IN_DEV_ARP_ANNOUNCE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_ANNOUNCE)
#define IN_DEV_ARP_IGNORE(in_dev) IN_DEV_MAXCONF((in_dev), ARP_IGNORE)
#define IN_DEV_ARP_NOTIFY(in_dev) IN_DEV_MAXCONF((in_dev), ARP_NOTIFY)
#define IN_DEV_NF_IPV4_DEFRAG_SKIP(in_dev) \
IN_DEV_ORCONF((in_dev), NF_IPV4_DEFRAG_SKIP)
struct in_ifaddr {
struct hlist_node hash;

View File

@ -169,6 +169,7 @@ enum
IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST,
IPV4_DEVCONF_DROP_GRATUITOUS_ARP,
IPV4_DEVCONF_BC_FORWARDING,
IPV4_DEVCONF_NF_IPV4_DEFRAG_SKIP,
__IPV4_DEVCONF_MAX
};

View File

@ -483,6 +483,7 @@ enum
NET_IPV4_CONF_PROMOTE_SECONDARIES=20,
NET_IPV4_CONF_ARP_ACCEPT=21,
NET_IPV4_CONF_ARP_NOTIFY=22,
NET_IPV4_CONF_NF_IPV4_DEFRAG_SKIP = 23,
};
/* /proc/sys/net/ipv4/netfilter */

View File

@ -257,6 +257,7 @@ static const struct bin_table bin_net_ipv4_conf_vars_table[] = {
{ CTL_INT, NET_IPV4_CONF_NOPOLICY, "disable_policy" },
{ CTL_INT, NET_IPV4_CONF_FORCE_IGMP_VERSION, "force_igmp_version" },
{ CTL_INT, NET_IPV4_CONF_PROMOTE_SECONDARIES, "promote_secondaries" },
{ CTL_INT, NET_IPV4_CONF_NF_IPV4_DEFRAG_SKIP, "nf_ipv4_defrag_skip" },
{}
};

View File

@ -2310,6 +2310,8 @@ static struct devinet_sysctl_table {
"route_localnet"),
DEVINET_SYSCTL_FLUSHING_ENTRY(DROP_UNICAST_IN_L2_MULTICAST,
"drop_unicast_in_l2_multicast"),
DEVINET_SYSCTL_RW_ENTRY(NF_IPV4_DEFRAG_SKIP,
"nf_ipv4_defrag_skip"),
},
};

View File

@ -11,6 +11,7 @@
#include <linux/netfilter.h>
#include <linux/module.h>
#include <linux/skbuff.h>
#include <linux/inetdevice.h>
#include <net/netns/generic.h>
#include <net/route.h>
#include <net/ip.h>
@ -83,8 +84,13 @@ static unsigned int ipv4_conntrack_defrag(void *priv,
#endif
/* Gather fragments. */
if (ip_is_fragment(ip_hdr(skb))) {
enum ip_defrag_users user =
nf_ct_defrag_user(state->hook, skb);
enum ip_defrag_users user;
if (skb->dev &&
IN_DEV_NF_IPV4_DEFRAG_SKIP(__in_dev_get_rcu(skb->dev)))
return NF_ACCEPT;
user = nf_ct_defrag_user(state->hook, skb);
if (nf_ct_ipv4_gather_frags(state->net, skb, user))
return NF_STOLEN;