aboutsummaryrefslogtreecommitdiffstats
path: root/testing/ipt-netflow-grsec
diff options
context:
space:
mode:
authorNatanael Copa <ncopa@alpinelinux.org>2017-02-14 18:36:19 +0000
committerNatanael Copa <ncopa@alpinelinux.org>2017-02-14 18:50:10 +0000
commit2b49e4cba6b4430543020f099a37c97a596e3533 (patch)
treeace835ec5d84de0cfb9565a98d1e259b6e66413d /testing/ipt-netflow-grsec
parent24733a94a24b056f175e65c0f4cb4903ee53e85c (diff)
testing/ipt-netflow-grsec: upgrade to 2.2 and 4.9.9 kernel
Diffstat (limited to 'testing/ipt-netflow-grsec')
-rw-r--r--testing/ipt-netflow-grsec/APKBUILD14
-rw-r--r--testing/ipt-netflow-grsec/git.patch3143
-rw-r--r--testing/ipt-netflow-grsec/kernel-4.6.patch63
3 files changed, 68 insertions, 3152 deletions
diff --git a/testing/ipt-netflow-grsec/APKBUILD b/testing/ipt-netflow-grsec/APKBUILD
index a7586dbc696..830eaff6e59 100644
--- a/testing/ipt-netflow-grsec/APKBUILD
+++ b/testing/ipt-netflow-grsec/APKBUILD
@@ -2,11 +2,11 @@
_flavor=grsec
_kpkg=linux-$_flavor
-_kver=4.4.47
+_kver=4.9.9
_kpkgrel=0
# when chaning _ver we *must* bump _mypkgrel
-_ver=2.1
+_ver=2.2
_mypkgrel=0
@@ -30,7 +30,7 @@ url="http://ipt-netflow.sourceforge.net/"
arch="all !aarch64"
license=GPL3+
source="ipt-netflow-$_ver.tar.gz::https://github.com/aabc/ipt-netflow/archive/v$_ver.tar.gz
- git.patch
+ kernel-4.6.patch
"
depends="$_kpkg-dev=$_kpkgver"
makedepends="linux-${_flavor}-dev=$_kpkgver iptables-dev bash"
@@ -65,9 +65,5 @@ dev() {
default_dev
}
-md5sums="bd8fc7d609c12832f5052f342640a839 ipt-netflow-2.1.tar.gz
-98c5286c6471e47d3bb25026ac406b30 git.patch"
-sha256sums="a3eafe7a09f09e15d330539fab983b88c887db56e5614bc820619e8462bc7749 ipt-netflow-2.1.tar.gz
-4d45daecb82ca29a513ebaed7c9bab91f0d16fa7834b52a7ff06dc0d1cd4cd3a git.patch"
-sha512sums="4ec48cb4612bd99d06ed2832d165fcddaf265f0c9555c7c49e012375c38c72cd57d5ee194a6b11e32eecfd2750e710a2bd167f3f2b2597b2e880a3f9b13ba27e ipt-netflow-2.1.tar.gz
-3714c78ae8e8ca432a3216c2067ec00f64f1e25985b39996907f4638835509ab587605937c81d823a9dc95cf3b963a0119eade75a3f2286d425aa0d333a44bc9 git.patch"
+sha512sums="e5d9039c079abfb2ef3656d96228616514ac57d87a9c71181f132ecac51e51407bcdc62aa6e1eb43d16f98be5b22d3801c58578317ea21aaa5433ed143daabe2 ipt-netflow-2.2.tar.gz
+96a250b87f8fb7d6240850dd0721aa0e1dcc7647b689abb15b07fb8758aea4338e5d169b3d0dca19e45279b38166d791cd0d412a9f4b44caf028cee2e782b72b kernel-4.6.patch"
diff --git a/testing/ipt-netflow-grsec/git.patch b/testing/ipt-netflow-grsec/git.patch
deleted file mode 100644
index 643da202c62..00000000000
--- a/testing/ipt-netflow-grsec/git.patch
+++ /dev/null
@@ -1,3143 +0,0 @@
-diff --git a/CREDITS b/CREDITS
-index 51e736e..e3fb344 100644
---- a/CREDITS
-+++ b/CREDITS
-@@ -48,6 +48,12 @@ Principal author and project maintainer:
- ABC <abc@telekom.ru> [2008-2015]
-
-
-+Compatibility layer is using code from Linux Kernel and should be
-+attributed to respective Linux developers.
-+
-+MurmurHash3 is based on smhasher (2012) of Austin Appleby.
-+
-+
- Patch authors and submitters:
-
- Ilya Evseev [2010]
-@@ -82,6 +88,7 @@ Extensive testing and other help:
- Andrew Savin @ Starlink [2014]
- Alexander Zakharov @ WAW Technologies [2015]
- Ivanov Eduard [2015]
-+ Maciej Zdeb [2015]
-
-
- (Send your names, emails, or nicks to add to the list.)
-diff --git a/Makefile.in b/Makefile.in
-index e96d50b..d72cb90 100644
---- a/Makefile.in
-+++ b/Makefile.in
-@@ -20,15 +20,18 @@ ccflags-y = @KOPTS@
-
- all: ipt_NETFLOW.ko libipt_NETFLOW.so libip6t_NETFLOW.so @SNMPTARGET@
-
--ipt_NETFLOW.ko: version.h ipt_NETFLOW.c ipt_NETFLOW.h Makefile
-+ipt_NETFLOW.ko: version.h ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile
- @echo Compiling for kernel $(KVERSION)
- make -C $(KDIR) M=$(CURDIR) modules CONFIG_DEBUG_INFO=y
- @touch $@
--sparse: | version.h ipt_NETFLOW.c ipt_NETFLOW.h Makefile
-+sparse: | version.h ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile
- @rm -f ipt_NETFLOW.ko ipt_NETFLOW.o
- @echo Compiling for kernel $(KVERSION)
- make -C $(KDIR) M=$(CURDIR) modules C=1
- @touch ipt_NETFLOW.ko
-+coverity:
-+ coverity-submit -v
-+
- minstall: | ipt_NETFLOW.ko
- @echo " *"
- make -C $(KDIR) M=$(CURDIR) modules_install INSTALL_MOD_PATH=$(DESTDIR)
-@@ -66,7 +69,7 @@ sinstall: | snmp_NETFLOW.so IPT-NETFLOW-MIB.my
- %.so: %_sh.o
- gcc -shared -o $@ $<
-
--version.h: ipt_NETFLOW.c ipt_NETFLOW.h Makefile
-+version.h: ipt_NETFLOW.c ipt_NETFLOW.h compat.h Makefile
- @./version.sh --define > version.h
-
- linstall: | libipt_NETFLOW.so libip6t_NETFLOW.so
-@@ -113,3 +116,8 @@ unload:
- -rmmod ipt_NETFLOW.ko
-
- reload: unload load
-+
-+ChangeLog:
-+ gitlog-to-changelog > ChangeLog
-+.PHONY: ChangeLog
-+
-diff --git a/README b/README
-index d524b17..c82cdf7 100644
---- a/README
-+++ b/README
-@@ -1,4 +1,4 @@
--ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
-+ipt_NETFLOW linux 2.6.x-4.x kernel module by <abc@telekom.ru> -- 2008-2015.
-
- High performance NetFlow v5, v9, IPFIX flow data export module for Linux
- kernel. Created to be useful for highly loaded linux router. It should be
-@@ -39,9 +39,9 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
- Such as metering, exporting, sampling stat and reliability stat, sampling
- configuration, network devices ifName, ifDescr list.
-
-- * Tested to compile and work out of the box on Centos 5, 6, 7, and Debian.
-- Many vanilla Linux kernels since 2.6.18 up to the latest (as of writing
-- is 3.16) are supported and tested.
-+ * Tested to compile and work out of the box on Centos 5, 6, 7, Debian and
-+ * Ubuntu. Many vanilla Linux kernels since 2.6.18 up to the latest (as of
-+ * writing is 3.19) are supported and tested.
-
- * Module load time and run-time (via sysctl) configuration.
-
-@@ -52,14 +52,15 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
- * SNMP-index translation rules, let convert meaningless and unstable
- interface indexes (ifIndex) to more meaningful numbering scheme.
-
-- * Easy support for catching mirrored traffic with promisc option.
-+ * Easy support for catching mirrored traffic with promisc option. Which is
-+ also supporting optional MPLS decapsulation and MPLS-aware NetFlow.
-
-
- ============================
- = OBTAINING LATEST VERSION =
- ============================
-
-- $ git clone git://git.code.sf.net/p/ipt-netflow/code ipt-netflow
-+ $ git clone git://github.com/aabc/ipt-netflow.git ipt-netflow
- $ cd ipt-netflow
-
-
-@@ -79,7 +80,7 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
-
- ~# yum install kernel-devel
-
-- b) What to do for Debian:
-+ b) What to do for Debian and Ubuntu:
-
- ~# apt-get install module-assistant
- ~# m-a prepare
-@@ -118,7 +119,7 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
-
- # yum install iptables-devel
-
-- b) What to do for Debian:
-+ b) What to do for Debian or Ubuntu:
-
- # apt-get install iptables-dev pkg-config
-
-@@ -134,7 +135,7 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
-
- # yum install net-snmp net-snmp-devel
-
-- b) For Debian:
-+ b) For Debian or Ubuntu:
-
- # apt-get install snmpd libsnmp-dev
-
-@@ -161,6 +162,14 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
- c) If you have sources in non-standard places or configure isn't able to
- find something run ./configure --help to see how to specify paths manually.
-
-+ d) To run irqtop on Debian 8 you may need to install:
-+
-+ # apt-get install ruby ruby-dev ncurses-dev
-+ # gem install curses
-+
-+ z) If all fails create ticket at
-+ https://github.com/aabc/ipt-netflow/issues
-+
- ** 5. After this point you should be able to load module and
- use -j NETFLOW target in your iptables. See next section.
-
-@@ -227,6 +236,25 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
- only disable auto-install into DKMS, but still create dkms.conf, in
- case you will want to install it manually.
-
-+ --enable-physdev
-+ Export ingressPhysicalInterface(252) and egressPhysicalInterface(253)
-+ (relevant for bridges) in V9 and IPFIX. If your collector does not
-+ support these Elements but you still need physdevs then use
-+ --enable-physdev-override, in that case physdevs will override normal
-+ interface numbers ingressInterface(10) and egressInterface(14).
-+
-+ --enable-promisc
-+ Enables capturing of promiscuous packets into raw/PREROUTING chain.
-+ See README.promisc Solution 1 for usage details and example.
-+
-+ --promisc-mpls
-+ Enables MPLS label stack decapsulation for promiscuous packets. (For
-+ IPv4 and IPv6 packets only). This also enables MPLS-aware NetFlow (v9
-+ and IPFIX), you may wish to specify with --promisc-mpls=n how much MPLS
-+ labels you want to be recorded and exported (default is 3, maximum is
-+ 10, set to 0 to not report anything).
-+
-+
- ===========
- = RUNNING =
- ===========
-@@ -381,10 +409,15 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
- because NetFlow v5 isn't compatible with IPv6.
-
- destination=127.0.0.1:2055
-- - where to export netflow, to this ip address
-- You will see this connection in netstat like this:
-+ - where to export netflow, to this ip address. Port is optional, default
-+ is 2055. You will see this connection in netstat like this:
-+
- udp 0 0 127.0.0.1:32772 127.0.0.1:2055 ESTABLISHED
-
-+ destination=[2001:db8::1]:2055
-+ - export target using IPv6 address. Brackets are optional, but otherwise
-+ you should delimit port with 'p' or '#' character.
-+
- destination=127.0.0.1:2055,192.0.0.1:2055
- - mirror flows to two (can be more) addresses, separate addresses
- with comma.
-@@ -523,13 +556,25 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
- snmp-rules are compilation disabled by default, to enable you will need
- to add --enable-snmp option to ./configure script.
-
-- scan-min = 1
-+ scan-min=1
- - Minimal interval between flow export scans. Sometimes could be useful
- to reduce load on exporting CPU by increasing this interval. Value are
- in kernel jiffies units (which is x/HZ seconds).
-
-- promisc = 1
-- - Enable promisc hack. See README.promisc Solution.1 for details.
-+ promisc=1
-+ - Enables promisc hack. See README.promisc Solution 1 for details.
-+
-+ exportcpu=number
-+ - Lock exporter to single CPU. This may be useful to fine control CPU
-+ load. Common use case: with smp_affinity and RSS you spread packet
-+ processing to all CPUs except one, and lock it to the exporter. While
-+ exporter CPU load generally is not high, for someone it may be not
-+ desirable to combine it with packet processing on very highly loaded
-+ routers.
-+
-+ This option also could be changed at runtime with:
-+
-+ # echo number > /sys/module/ipt_NETFLOW/parameters/exportcpu
-
-
- ====================
-@@ -722,17 +767,26 @@ ipt_NETFLOW linux 2.6.x-3.x kernel module by <abc@telekom.ru> -- 2008-2015.
- IP TOS: ipClassOfService(5),
- and address family (IP or IPv6).
-
-- If VLAN exporting is enabled:
-+ Additional Flow Keys if VLAN exporting is enabled:
-+
- First (outer) dot1q VLAN tag: dot1qVlanId(243) and
- dot1qPriority(244) for IPFIX,
- or vlanId(243) for NetFlow v9.
- Second (customer) dot1q VLAN tag: dot1qCustomerVlanId(245)
- and dot1qCustomerPriority(246).
-
-- If MAC address exporting is enabled:
-+ Additional Flow Keys if MAC address exporting is enabled:
-+
- Destination MAC address: destinationMacAddress(80),
- Source MAC address: sourceMacAddress(56).
-
-+ Additional Flow Keys if MPLS-aware NetFlow is enabled:
-+
-+ Captured MPLS stack is fully treated as flow key (including TTL values),
-+ which is Elements from mplsTopLabelStackSection(70) to
-+ mplsLabelStackSection10(79), and, if present, mplsTopLabelTTL(200).
-+
-+
- Other Elements are not Flow Keys. Note that outer interface, which is
- egressInterface(14), is not regarded as Flow Key. Quoting RFC 7012: "For
- Information Elements ... for which the value may change from packet to packet
-diff --git a/compat.h b/compat.h
-new file mode 100644
-index 0000000..2b05994
---- /dev/null
-+++ b/compat.h
-@@ -0,0 +1,598 @@
-+/* This code is derived from the Linux Kernel sources intended
-+ * to maintain compatibility with different Kernel versions.
-+ * Copyright of original source is of respective Linux Kernel authors.
-+ * License is GPLv2.
-+ */
-+
-+#ifndef COMPAT_NETFLOW_H
-+#define COMPAT_NETFLOW_H
-+
-+
-+#ifndef NIPQUAD
-+# define NIPQUAD(addr) \
-+ ((unsigned char *)&addr)[0], \
-+ ((unsigned char *)&addr)[1], \
-+ ((unsigned char *)&addr)[2], \
-+ ((unsigned char *)&addr)[3]
-+#endif
-+#ifndef HIPQUAD
-+# if defined(__LITTLE_ENDIAN)
-+# define HIPQUAD(addr) \
-+ ((unsigned char *)&addr)[3], \
-+ ((unsigned char *)&addr)[2], \
-+ ((unsigned char *)&addr)[1], \
-+ ((unsigned char *)&addr)[0]
-+# elif defined(__BIG_ENDIAN)
-+# define HIPQUAD NIPQUAD
-+# else
-+# error "Please fix asm/byteorder.h"
-+# endif /* __LITTLE_ENDIAN */
-+#endif
-+
-+#ifndef IPT_CONTINUE
-+# define IPT_CONTINUE XT_CONTINUE
-+# define ipt_target xt_target
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
-+union nf_inet_addr {
-+ __be32 ip;
-+ __be32 ip6[4];
-+ struct in_addr in;
-+ struct in6_addr in6;
-+};
-+#endif
-+
-+#ifndef list_first_entry
-+#define list_first_entry(ptr, type, member) \
-+ list_entry((ptr)->next, type, member)
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-+# define INIT_NET(x) x
-+#else
-+# define INIT_NET(x) init_net.x
-+#endif
-+
-+#ifndef ETH_P_8021AD
-+# define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
-+#endif
-+
-+#ifndef ETH_P_QINQ1
-+# define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN */
-+# define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN */
-+# define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN */
-+#endif
-+
-+#ifndef IPPROTO_MH
-+# define IPPROTO_MH 135
-+#endif
-+
-+#ifdef CONFIG_SYSCTL
-+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-+# define BEFORE2632(x,y) x,y
-+# else /* since 2.6.32 */
-+# define BEFORE2632(x,y)
-+# endif
-+
-+# if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
-+# define ctl_table struct ctl_table
-+# endif
-+
-+# ifndef HAVE_GRSECURITY_H
-+# define ctl_table_no_const ctl_table
-+# endif
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
-+# define compat_hlist_for_each_entry hlist_for_each_entry
-+# define compat_hlist_for_each_entry_safe hlist_for_each_entry_safe
-+#else /* since 3.9.0 */
-+# define compat_hlist_for_each_entry(a,pos,c,d) hlist_for_each_entry(a,c,d)
-+# define compat_hlist_for_each_entry_safe(a,pos,c,d,e) hlist_for_each_entry_safe(a,c,d,e)
-+#endif
-+
-+#ifndef WARN_ONCE
-+#define WARN_ONCE(x,fmt...) ({ if (x) printk(KERN_WARNING fmt); })
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
-+# define IPPROTO_UDPLITE 136
-+#endif
-+
-+#ifndef time_is_before_jiffies
-+# define time_is_before_jiffies(a) time_after(jiffies, a)
-+#endif
-+#ifndef time_is_after_jiffies
-+# define time_is_after_jiffies(a) time_before(jiffies, a)
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
-+# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+# define prandom_u32 get_random_int
-+# elif LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
-+# define prandom_u32 random32
-+#endif
-+#define prandom_u32_max compat_prandom_u32_max
-+static inline u32 prandom_u32_max(u32 ep_ro)
-+{
-+ return (u32)(((u64) prandom_u32() * ep_ro) >> 32);
-+}
-+#endif
-+
-+#ifndef min_not_zero
-+# define min_not_zero(x, y) ({ \
-+ typeof(x) __x = (x); \
-+ typeof(y) __y = (y); \
-+ __x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); })
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)
-+static int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
-+{
-+ ASSERT_RTNL();
-+
-+ if (!dev->ethtool_ops->get_settings)
-+ return -EOPNOTSUPP;
-+
-+ memset(cmd, 0, sizeof(struct ethtool_cmd));
-+ cmd->cmd = ETHTOOL_GSET;
-+ return dev->ethtool_ops->get_settings(dev, cmd);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
-+# define ethtool_cmd_speed(x) (x)->speed
-+#endif
-+
-+#ifndef ARPHRD_PHONET
-+# define ARPHRD_PHONET 820
-+# define ARPHRD_PHONET_PIPE 821
-+#endif
-+#ifndef ARPHRD_IEEE802154
-+# define ARPHRD_IEEE802154 804
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
-+# define for_each_netdev_ns(net, dev) for (dev = dev_base; dev; dev = dev->next)
-+#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-+# define for_each_netdev_ns(net, d) for_each_netdev(d)
-+#else
-+# define for_each_netdev_ns(net, d) for_each_netdev(net, d)
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
-+# define CHECK_FAIL 0
-+# define CHECK_OK 1
-+#else
-+# define CHECK_FAIL -EINVAL
-+# define CHECK_OK 0
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
-+# define use_module ref_module
-+#endif
-+
-+#ifndef NF_IP_LOCAL_IN /* 2.6.25 */
-+# define NF_IP_PRE_ROUTING NF_INET_PRE_ROUTING
-+# define NF_IP_LOCAL_IN NF_INET_LOCAL_IN
-+# define NF_IP_FORWARD NF_INET_FORWARD
-+# define NF_IP_LOCAL_OUT NF_INET_LOCAL_OUT
-+# define NF_IP_POST_ROUTING NF_INET_POST_ROUTING
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
-+/* net/netfilter/x_tables.c */
-+static void xt_unregister_targets(struct xt_target *target, unsigned int n)
-+{
-+ unsigned int i;
-+
-+ for (i = 0; i < n; i++)
-+ xt_unregister_target(&target[i]);
-+}
-+static int xt_register_targets(struct xt_target *target, unsigned int n)
-+{
-+ unsigned int i;
-+
-+ int err = 0;
-+ for (i = 0; i < n; i++)
-+ if ((err = xt_register_target(&target[i])))
-+ goto err;
-+ return err;
-+err:
-+ if (i > 0)
-+ xt_unregister_targets(target, i);
-+ return err;
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
-+#define num_physpages totalram_pages
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
-+# ifdef ktime_to_timeval
-+/* ktime_to_timeval is defined on 64bit and inline on 32bit cpu */
-+/* when it's defined it calls ns_to_timeval, which is not exported */
-+struct timeval portable_ns_to_timeval(const s64 nsec)
-+{
-+ struct timespec ts = ns_to_timespec(nsec);
-+ struct timeval tv;
-+
-+ tv.tv_sec = ts.tv_sec;
-+ tv.tv_usec = (suseconds_t) ts.tv_nsec / 1000;
-+
-+ return tv;
-+}
-+# define ns_to_timeval portable_ns_to_timeval
-+# endif
-+
-+static inline s64 portable_ktime_to_ms(const ktime_t kt)
-+{
-+ struct timeval tv = ktime_to_timeval(kt);
-+ return (s64) tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC;
-+}
-+# define ktime_to_ms portable_ktime_to_ms
-+#endif /* before 2.6.35 */
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
-+static inline s64 portable_ktime_to_us(const ktime_t kt)
-+{
-+ struct timeval tv = ktime_to_timeval(kt);
-+ return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
-+}
-+#define ktime_to_us portable_ktime_to_us
-+#endif
-+
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
-+static inline void put_unaligned_be16(u16 val, void *p)
-+{
-+ put_unaligned(cpu_to_be16(val), (__be16 *)p);
-+}
-+static inline void put_unaligned_be32(u32 val, void *p)
-+{
-+ put_unaligned(cpu_to_be32(val), (__be32 *)p);
-+}
-+static inline void put_unaligned_be64(u64 val, void *p)
-+{
-+ put_unaligned(cpu_to_be64(val), (__be64 *)p);
-+}
-+#endif
-+
-+#if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,24) && !defined(RHEL_MAJOR)
-+static void *__seq_open_private(struct file *f, struct seq_operations *ops,
-+ int psize)
-+{
-+ int rc;
-+ void *private;
-+ struct seq_file *seq;
-+
-+ private = kzalloc(psize, GFP_KERNEL);
-+ if (private == NULL)
-+ goto out;
-+
-+ rc = seq_open(f, ops);
-+ if (rc < 0)
-+ goto out_free;
-+
-+ seq = f->private_data;
-+ seq->private = private;
-+ return private;
-+
-+out_free:
-+ kfree(private);
-+out:
-+ return NULL;
-+}
-+#endif
-+
-+/* disappeared in v3.19 */
-+#ifndef __get_cpu_var
-+#define __get_cpu_var(var) (*this_cpu_ptr(&(var)))
-+#endif
-+
-+#ifndef MPLS_HLEN
-+#define MPLS_HLEN 4
-+static inline int eth_p_mpls(__be16 eth_type)
-+{
-+ return eth_type == htons(ETH_P_MPLS_UC) ||
-+ eth_type == htons(ETH_P_MPLS_MC);
-+}
-+#endif
-+#ifndef MPLS_LS_S_MASK
-+struct mpls_label {
-+ __be32 entry;
-+};
-+#define MPLS_LS_S_MASK 0x00000100
-+
-+#endif
-+
-+/* sockaddr comparison functions is from fs/nfs/client.c */
-+static int sockaddr_match_ipaddr6(const struct sockaddr *sa1, const struct sockaddr *sa2)
-+{
-+ const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
-+ const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
-+
-+ if (!ipv6_addr_equal(&sin1->sin6_addr, &sin2->sin6_addr))
-+ return 0;
-+#if 0
-+ else if (ipv6_addr_type(&sin1->sin6_addr) & IPV6_ADDR_LINKLOCAL)
-+ return sin1->sin6_scope_id == sin2->sin6_scope_id;
-+#endif
-+ return 1;
-+}
-+
-+static int sockaddr_match_ipaddr4(const struct sockaddr *sa1, const struct sockaddr *sa2)
-+{
-+ const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
-+ const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
-+
-+ return sin1->sin_addr.s_addr == sin2->sin_addr.s_addr;
-+}
-+
-+static int sockaddr_cmp_ip6(const struct sockaddr *sa1, const struct sockaddr *sa2)
-+{
-+ const struct sockaddr_in6 *sin1 = (const struct sockaddr_in6 *)sa1;
-+ const struct sockaddr_in6 *sin2 = (const struct sockaddr_in6 *)sa2;
-+
-+ return sockaddr_match_ipaddr6(sa1, sa2) &&
-+ (sin1->sin6_port == sin2->sin6_port);
-+}
-+
-+static int sockaddr_cmp_ip4(const struct sockaddr *sa1, const struct sockaddr *sa2)
-+{
-+ const struct sockaddr_in *sin1 = (const struct sockaddr_in *)sa1;
-+ const struct sockaddr_in *sin2 = (const struct sockaddr_in *)sa2;
-+
-+ return sockaddr_match_ipaddr4(sa1, sa2) &&
-+ (sin1->sin_port == sin2->sin_port);
-+}
-+
-+static int sockaddr_cmp(const struct sockaddr_storage *sa1, const struct sockaddr_storage *sa2)
-+{
-+ const struct sockaddr *s1 = (const struct sockaddr *)sa1;
-+ const struct sockaddr *s2 = (const struct sockaddr *)sa2;
-+
-+ if (sa1->ss_family != sa2->ss_family)
-+ return 0;
-+
-+ switch (sa1->ss_family) {
-+ case AF_INET:
-+ return sockaddr_cmp_ip4(s1, s2);
-+ case AF_INET6:
-+ return sockaddr_cmp_ip6(s1, s2);
-+ }
-+ return 0;
-+}
-+
-+#ifndef IN6PTON_XDIGIT
-+#define hex_to_bin compat_hex_to_bin
-+/* lib/hexdump.c */
-+int hex_to_bin(char ch)
-+{
-+ if ((ch >= '0') && (ch <= '9'))
-+ return ch - '0';
-+ ch = tolower(ch);
-+ if ((ch >= 'a') && (ch <= 'f'))
-+ return ch - 'a' + 10;
-+ return -1;
-+}
-+
-+/* net/core/utils.c */
-+#define IN6PTON_XDIGIT 0x00010000
-+#define IN6PTON_DIGIT 0x00020000
-+#define IN6PTON_COLON_MASK 0x00700000
-+#define IN6PTON_COLON_1 0x00100000 /* single : requested */
-+#define IN6PTON_COLON_2 0x00200000 /* second : requested */
-+#define IN6PTON_COLON_1_2 0x00400000 /* :: requested */
-+#define IN6PTON_DOT 0x00800000 /* . */
-+#define IN6PTON_DELIM 0x10000000
-+#define IN6PTON_NULL 0x20000000 /* first/tail */
-+#define IN6PTON_UNKNOWN 0x40000000
-+
-+static inline int xdigit2bin(char c, int delim)
-+{
-+ int val;
-+
-+ if (c == delim || c == '\0')
-+ return IN6PTON_DELIM;
-+ if (c == ':')
-+ return IN6PTON_COLON_MASK;
-+ if (c == '.')
-+ return IN6PTON_DOT;
-+
-+ val = hex_to_bin(c);
-+ if (val >= 0)
-+ return val | IN6PTON_XDIGIT | (val < 10 ? IN6PTON_DIGIT : 0);
-+
-+ if (delim == -1)
-+ return IN6PTON_DELIM;
-+ return IN6PTON_UNKNOWN;
-+}
-+
-+int in4_pton(const char *src, int srclen,
-+ u8 *dst,
-+ int delim, const char **end)
-+{
-+ const char *s;
-+ u8 *d;
-+ u8 dbuf[4];
-+ int ret = 0;
-+ int i;
-+ int w = 0;
-+
-+ if (srclen < 0)
-+ srclen = strlen(src);
-+ s = src;
-+ d = dbuf;
-+ i = 0;
-+ while(1) {
-+ int c;
-+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
-+ if (!(c & (IN6PTON_DIGIT | IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK))) {
-+ goto out;
-+ }
-+ if (c & (IN6PTON_DOT | IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
-+ if (w == 0)
-+ goto out;
-+ *d++ = w & 0xff;
-+ w = 0;
-+ i++;
-+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
-+ if (i != 4)
-+ goto out;
-+ break;
-+ }
-+ goto cont;
-+ }
-+ w = (w * 10) + c;
-+ if ((w & 0xffff) > 255) {
-+ goto out;
-+ }
-+cont:
-+ if (i >= 4)
-+ goto out;
-+ s++;
-+ srclen--;
-+ }
-+ ret = 1;
-+ memcpy(dst, dbuf, sizeof(dbuf));
-+out:
-+ if (end)
-+ *end = s;
-+ return ret;
-+}
-+
-+int in6_pton(const char *src, int srclen,
-+ u8 *dst,
-+ int delim, const char **end)
-+{
-+ const char *s, *tok = NULL;
-+ u8 *d, *dc = NULL;
-+ u8 dbuf[16];
-+ int ret = 0;
-+ int i;
-+ int state = IN6PTON_COLON_1_2 | IN6PTON_XDIGIT | IN6PTON_NULL;
-+ int w = 0;
-+
-+ memset(dbuf, 0, sizeof(dbuf));
-+
-+ s = src;
-+ d = dbuf;
-+ if (srclen < 0)
-+ srclen = strlen(src);
-+
-+ while (1) {
-+ int c;
-+
-+ c = xdigit2bin(srclen > 0 ? *s : '\0', delim);
-+ if (!(c & state))
-+ goto out;
-+ if (c & (IN6PTON_DELIM | IN6PTON_COLON_MASK)) {
-+ /* process one 16-bit word */
-+ if (!(state & IN6PTON_NULL)) {
-+ *d++ = (w >> 8) & 0xff;
-+ *d++ = w & 0xff;
-+ }
-+ w = 0;
-+ if (c & IN6PTON_DELIM) {
-+ /* We've processed last word */
-+ break;
-+ }
-+ /*
-+ * COLON_1 => XDIGIT
-+ * COLON_2 => XDIGIT|DELIM
-+ * COLON_1_2 => COLON_2
-+ */
-+ switch (state & IN6PTON_COLON_MASK) {
-+ case IN6PTON_COLON_2:
-+ dc = d;
-+ state = IN6PTON_XDIGIT | IN6PTON_DELIM;
-+ if (dc - dbuf >= sizeof(dbuf))
-+ state |= IN6PTON_NULL;
-+ break;
-+ case IN6PTON_COLON_1|IN6PTON_COLON_1_2:
-+ state = IN6PTON_XDIGIT | IN6PTON_COLON_2;
-+ break;
-+ case IN6PTON_COLON_1:
-+ state = IN6PTON_XDIGIT;
-+ break;
-+ case IN6PTON_COLON_1_2:
-+ state = IN6PTON_COLON_2;
-+ break;
-+ default:
-+ state = 0;
-+ }
-+ tok = s + 1;
-+ goto cont;
-+ }
-+
-+ if (c & IN6PTON_DOT) {
-+ ret = in4_pton(tok ? tok : s, srclen + (int)(s - tok), d, delim, &s);
-+ if (ret > 0) {
-+ d += 4;
-+ break;
-+ }
-+ goto out;
-+ }
-+
-+ w = (w << 4) | (0xff & c);
-+ state = IN6PTON_COLON_1 | IN6PTON_DELIM;
-+ if (!(w & 0xf000)) {
-+ state |= IN6PTON_XDIGIT;
-+ }
-+ if (!dc && d + 2 < dbuf + sizeof(dbuf)) {
-+ state |= IN6PTON_COLON_1_2;
-+ state &= ~IN6PTON_DELIM;
-+ }
-+ if (d + 2 >= dbuf + sizeof(dbuf)) {
-+ state &= ~(IN6PTON_COLON_1|IN6PTON_COLON_1_2);
-+ }
-+cont:
-+ if ((dc && d + 4 < dbuf + sizeof(dbuf)) ||
-+ d + 4 == dbuf + sizeof(dbuf)) {
-+ state |= IN6PTON_DOT;
-+ }
-+ if (d >= dbuf + sizeof(dbuf)) {
-+ state &= ~(IN6PTON_XDIGIT|IN6PTON_COLON_MASK);
-+ }
-+ s++;
-+ srclen--;
-+ }
-+
-+ i = 15; d--;
-+
-+ if (dc) {
-+ while(d >= dc)
-+ dst[i--] = *d--;
-+ while(i >= dc - dbuf)
-+ dst[i--] = 0;
-+ while(i >= 0)
-+ dst[i--] = *d--;
-+ } else
-+ memcpy(dst, dbuf, sizeof(dbuf));
-+
-+ ret = 1;
-+out:
-+ if (end)
-+ *end = s;
-+ return ret;
-+}
-+#endif /* IN6PTON_XDIGIT */
-+
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,2,0)
-+# define sock_create_kern(f, t, p, s) sock_create_kern(&init_net, f, t, p, s)
-+#endif
-+
-+#if !defined(vlan_tx_tag_get) && defined(skb_vlan_tag_get)
-+# define vlan_tx_tag_get skb_vlan_tag_get
-+# define vlan_tx_tag_present skb_vlan_tag_present
-+#endif
-+
-+#ifndef NF_HOOK
-+# define NF_HOOK_COMPAT NF_HOOK
-+#else
-+# define NF_HOOK_COMPAT(a,b,c,d,e,f,g) NF_HOOK(a,b,d,e,f,g)
-+#endif
-+
-+#endif /* COMPAT_NETFLOW_H */
-diff --git a/configure b/configure
-index 30a928c..1278c61 100755
---- a/configure
-+++ b/configure
-@@ -263,7 +263,6 @@ show_help() {
- echo " --kver=.. kernel version (ex.: 2.6.30-std-def-alt15)"
- echo " --kdir=.. directory for kernel source (ex.: /usr/src/kernel)"
- echo " --enable-natevents enables natevents support"
-- echo " --enable-debugfs enables debugfs support for flow lists"
- echo " --enable-snmp-rules enables SNMP-index conversion rules"
- echo " --enable-macaddress enables MAC address for v9/IPFIX"
- echo " --enable-vlan enables VLAN Ids for v9/IPFIX"
-@@ -271,7 +270,11 @@ show_help() {
- echo " --enable-sampler enables Flow Sampling"
- echo " --enable-sampler=hash enables Hash sampler"
- echo " --enable-aggregation enables aggregation rules"
-- echo " --enable-promisc enables promisc hack"
-+ echo " --enable-promisc enables promisc hack mode"
-+ echo " --promisc-mpls decapsulate MPLS in promisc mode"
-+ echo " --promisc-mpls=N -- and record N labels (default 3)"
-+ echo " --enable-physdev enables physdev reporting"
-+ echo " --enable-physdev-override to override interfaces"
- echo " --disable-snmp-agent disables net-snmp agent"
- echo " --disable-dkms disables DKMS support completely"
- echo " --disable-dkms-install no DKMS install but still create dkms.conf"
-@@ -295,15 +298,17 @@ do
- --kver=*) KVERSION="$ac_optarg" ;;
- --kdir=*) KDIR="$ac_optarg" ;;
- --enable-nat*) KOPTS="$KOPTS -DENABLE_NAT" ;;
-- --enable-debug*) KOPTS="$KOPTS -DENABLE_DEBUGFS" ;;
- --enable-mac*) KOPTS="$KOPTS -DENABLE_MAC" ;;
- --enable-vlan*) KOPTS="$KOPTS -DENABLE_VLAN" ;;
- --enable-direc*) KOPTS="$KOPTS -DENABLE_DIRECTION" ;;
- --enable-sampl*hash) KOPTS="$KOPTS -DENABLE_SAMPLER -DSAMPLING_HASH" ;;
- --enable-sampl*) KOPTS="$KOPTS -DENABLE_SAMPLER" ;;
- --enable-aggr*) KOPTS="$KOPTS -DENABLE_AGGR" ;;
-- --enable-promi*) KOPTS="$KOPTS -DENABLE_PROMISC" ;;
-+ --enable-promi*) ENABLE_PROMISC=1 ;;
-+ --promisc-mpls*) ENABLE_PROMISC=1; PROMISC_MPLS=1; MPLS_DEPTH="$ac_optarg" ;;
- --enable-snmp-r*) KOPTS="$KOPTS -DENABLE_SNMP" ;;
-+ --enable-physdev) KOPTS="$KOPTS -DENABLE_PHYSDEV" ;;
-+ --enable-physdev-over*) KOPTS="$KOPTS -DENABLE_PHYSDEV_OVER" ;;
- --disable-snmp-a*) SKIPSNMP=1 ;;
- --disable-net-snmp*) SKIPSNMP=1 ;;
- --disable-dkms*) SKIPDKMS=1 ;;
-@@ -316,6 +321,18 @@ do
- esac
- done
-
-+if [ "$ENABLE_PROMISC" = 1 ]; then KOPTS="$KOPTS -DENABLE_PROMISC"; fi
-+if [ "$PROMISC_MPLS" = 1 ]; then
-+ KOPTS="$KOPTS -DPROMISC_MPLS"
-+ if [ "$MPLS_DEPTH" -gt 10 ]; then
-+ echo "! Requested MPLS stack depth is too big, limiting to 10."
-+ MPLS_DEPTH=10;
-+ elif [ ! "$MPLS_DEPTH" ]; then
-+ MPLS_DEPTH=3
-+ fi
-+ if [ "$MPLS_DEPTH" -ge 1 ]; then KOPTS="$KOPTS -DMPLS_DEPTH=$MPLS_DEPTH"; fi
-+fi
-+
- kernel_find_version() {
- KHOW=requested
- test "$KVERSION" && return 0
-@@ -436,6 +453,7 @@ kernel_check_include() {
-
- kernel_check_features() {
- kernel_check_include include/linux/llist.h -DHAVE_LLIST
-+ kernel_check_include include/linux/grsecurity.h -DHAVE_GRSECURITY_H
- }
-
- snmp_check() {
-diff --git a/ipt_NETFLOW.c b/ipt_NETFLOW.c
-index f6bd7a8..2d5e95b 100644
---- a/ipt_NETFLOW.c
-+++ b/ipt_NETFLOW.c
-@@ -26,6 +26,8 @@
- #include <linux/seq_file.h>
- #include <linux/random.h>
- #include <linux/in6.h>
-+#include <linux/inet.h>
-+#include <linux/kernel.h>
- #include <linux/ip.h>
- #include <linux/udp.h>
- #include <linux/icmp.h>
-@@ -51,69 +53,37 @@
- #ifndef ENABLE_NAT
- # undef CONFIG_NF_NAT_NEEDED
- #endif
--#ifdef ENABLE_VLAN
--#include <linux/if_vlan.h>
-+#if defined(ENABLE_VLAN) || defined(ENABLE_PROMISC)
-+# include <linux/if_vlan.h>
- #endif
- #ifdef ENABLE_MAC
--#include <linux/if_ether.h>
--#include <linux/etherdevice.h>
-+# include <linux/if_ether.h>
-+# include <linux/etherdevice.h>
- #endif
- #if defined(CONFIG_NF_NAT_NEEDED)
--#include <linux/notifier.h>
--#include <net/netfilter/nf_conntrack.h>
--#include <net/netfilter/nf_conntrack_core.h>
-+# include <linux/notifier.h>
-+# include <net/netfilter/nf_conntrack.h>
-+# include <net/netfilter/nf_conntrack_core.h>
- #endif
- #include <linux/version.h>
- #include <asm/unaligned.h>
- #ifdef HAVE_LLIST
- /* llist.h is officially defined since linux 3.1,
- * but centos6 have it backported on its 2.6.32.el6 */
--#include <linux/llist.h>
-+# include <linux/llist.h>
- #endif
-+#include "compat.h"
- #include "ipt_NETFLOW.h"
- #include "murmur3.h"
- #ifdef CONFIG_BRIDGE_NETFILTER
--#include <linux/netfilter_bridge.h>
-+# include <linux/netfilter_bridge.h>
- #endif
- #ifdef CONFIG_SYSCTL
--#include <linux/sysctl.h>
--#endif
--#ifdef ENABLE_DEBUGFS
--# ifdef CONFIG_DEBUG_FS
--# include <linux/debugfs.h>
--# else
--# undef ENABLE_DEBUGFS
--# endif
-+# include <linux/sysctl.h>
- #endif
- #ifndef CONFIG_NF_CONNTRACK_EVENTS
- /* No conntrack events in the kernel imply no natevents. */
--#undef CONFIG_NF_NAT_NEEDED
--#endif
--
--#ifndef NIPQUAD
--#define NIPQUAD(addr) \
-- ((unsigned char *)&addr)[0], \
-- ((unsigned char *)&addr)[1], \
-- ((unsigned char *)&addr)[2], \
-- ((unsigned char *)&addr)[3]
--#endif
--#ifndef HIPQUAD
--#if defined(__LITTLE_ENDIAN)
--#define HIPQUAD(addr) \
-- ((unsigned char *)&addr)[3], \
-- ((unsigned char *)&addr)[2], \
-- ((unsigned char *)&addr)[1], \
-- ((unsigned char *)&addr)[0]
--#elif defined(__BIG_ENDIAN)
--#define HIPQUAD NIPQUAD
--#else
--#error "Please fix asm/byteorder.h"
--#endif /* __LITTLE_ENDIAN */
--#endif
--
--#ifndef IPT_CONTINUE
--#define IPT_CONTINUE XT_CONTINUE
--#define ipt_target xt_target
-+# undef CONFIG_NF_NAT_NEEDED
- #endif
-
- #define IPT_NETFLOW_VERSION "2.1" /* Note that if you are using git, you
-@@ -339,7 +309,7 @@ static int metric = METRIC_DFL,
-
- static int set_hashsize(int new_size);
- static void destination_removeall(void);
--static int add_destinations(char *ptr);
-+static int add_destinations(const char *ptr);
- static int netflow_scan_and_export(int flush);
- enum {
- DONT_FLUSH, AND_FLUSH
-@@ -351,10 +321,6 @@ static int tpl_count = 0; /* how much active templates */
- static unsigned long ts_stat_last = 0; /* (jiffies) */
- static unsigned long ts_sysinf_last = 0; /* (jiffies) */
- static unsigned long ts_ifnames_last = 0; /* (jiffies) */
--#ifdef ENABLE_DEBUGFS
--static atomic_t freeze = ATOMIC_INIT(0);
--static struct dentry *flows_dump_d;
--#endif
-
- static inline __be32 bits2mask(int bits) {
- return (bits? 0xffffffff << (32 - bits) : 0);
-@@ -424,12 +390,6 @@ static inline void pause_scan_worker(void)
- _unschedule_scan_worker();
- }
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
--#define INIT_NET(x) x
--#else
--#define INIT_NET(x) init_net.x
--#endif
--
- #ifdef ENABLE_SAMPLER
- static inline unsigned char get_sampler_mode(void)
- {
-@@ -457,6 +417,55 @@ static inline unsigned short sampler_nf_v5(void)
- }
- #endif
-
-+/* return value is different from usual snprintf */
-+static char *snprintf_sockaddr(char *buf, size_t len, const struct sockaddr_storage *ss)
-+{
-+#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
-+ if (ss->ss_family == AF_INET) {
-+ const struct sockaddr_in *sin = (struct sockaddr_in *)ss;
-+
-+ snprintf(buf, len, "%u.%u.%u.%u:%u",
-+ NIPQUAD(sin->sin_addr.s_addr),
-+ ntohs(sin->sin_port));
-+ } else if (ss->ss_family == AF_INET6) {
-+ const struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)ss;
-+
-+ snprintf(buf, len, "[%x:%x:%x:%x:%x:%x:%x:%x]:%u",
-+ ntohs(sin6->sin6_addr.s6_addr16[0]),
-+ ntohs(sin6->sin6_addr.s6_addr16[1]),
-+ ntohs(sin6->sin6_addr.s6_addr16[2]),
-+ ntohs(sin6->sin6_addr.s6_addr16[3]),
-+ ntohs(sin6->sin6_addr.s6_addr16[4]),
-+ ntohs(sin6->sin6_addr.s6_addr16[5]),
-+ ntohs(sin6->sin6_addr.s6_addr16[6]),
-+ ntohs(sin6->sin6_addr.s6_addr16[7]),
-+ ntohs(sin6->sin6_port));
-+ } else
-+ snprintf(buf, len, "(invalid address)");
-+#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,11,0)
-+ if (ss->ss_family == AF_INET)
-+ snprintf(buf, len, "%pI4:%u",
-+ &((const struct sockaddr_in *)ss)->sin_addr,
-+ ntohs(((const struct sockaddr_in *)ss)->sin_port));
-+ else if (ss->ss_family == AF_INET6)
-+ snprintf(buf, len, "[%pI6c]:%u",
-+ &((const struct sockaddr_in6 *)ss)->sin6_addr,
-+ ntohs(((const struct sockaddr_in6 *)ss)->sin6_port));
-+ else
-+ snprintf(buf, len, "(invalid address)");
-+#else
-+ snprintf(buf, len, "%pISpc", ss);
-+#endif
-+ return buf;
-+}
-+
-+static char *print_sockaddr(const struct sockaddr_storage *ss)
-+{
-+ static char buf[64];
-+
-+ return snprintf_sockaddr(buf, sizeof(buf), ss);
-+}
-+
- #ifdef CONFIG_PROC_FS
- static inline int ABS(int x) { return x >= 0 ? x : -x; }
- #define SAFEDIV(x,y) ((y)? ({ u64 __tmp = x; do_div(__tmp, y); (int)__tmp; }) : 0)
-@@ -561,10 +570,9 @@ static int snmp_seq_show(struct seq_file *seq, void *v)
-
- if (sndbuf_peak < wmem_peak)
- sndbuf_peak = wmem_peak;
-- seq_printf(seq, "sock%d %u.%u.%u.%u:%u %d %u %u %u %u",
-+ seq_printf(seq, "sock%d %s %d %u %u %u %u",
- snum,
-- HIPQUAD(usock->ipaddr),
-- usock->port,
-+ print_sockaddr(&usock->addr),
- !!usock->sock,
- usock->err_connect,
- usock->err_full,
-@@ -606,9 +614,6 @@ static int nf_seq_show(struct seq_file *seq, void *v)
- #ifdef ENABLE_AGGR
- " aggr"
- #endif
--#ifdef ENABLE_DEBUGFS
-- " debugfs"
--#endif
- #ifdef ENABLE_DIRECTION
- " dir"
- #endif
-@@ -623,6 +628,9 @@ static int nf_seq_show(struct seq_file *seq, void *v)
- #endif
- #ifdef ENABLE_PROMISC
- " promisc"
-+# ifdef PROMISC_MPLS
-+ "+mpls"
-+# endif
- #endif
- #ifdef ENABLE_SAMPLER
- " samp"
-@@ -808,10 +816,9 @@ static int nf_seq_show(struct seq_file *seq, void *v)
-
- mutex_lock(&sock_lock);
- list_for_each_entry(usock, &usock_list, list) {
-- seq_printf(seq, "sock%d: %u.%u.%u.%u:%u",
-+ seq_printf(seq, "sock%d: %s",
- snum,
-- HIPQUAD(usock->ipaddr),
-- usock->port);
-+ print_sockaddr(&usock->addr));
- if (usock->sock) {
- struct sock *sk = usock->sock->sk;
-
-@@ -902,110 +909,171 @@ static struct file_operations snmp_seq_fops = {
- .llseek = seq_lseek,
- .release = single_release,
- };
--#endif /* CONFIG_PROC_FS */
-
--#ifdef ENABLE_DEBUGFS
--static inline int active_needs_export(const struct ipt_netflow *nf, const long a_timeout, const unsigned long jiff);
-+static inline int inactive_needs_export(const struct ipt_netflow *nf, const long i_timeout,
-+ const unsigned long jiff);
-+static inline int active_needs_export(const struct ipt_netflow *nf, const long a_timeout,
-+ const unsigned long jiff);
- static inline u_int32_t hash_netflow(const struct ipt_netflow_tuple *tuple);
-
--static int seq_stripe = -1;
-+struct flows_dump_private {
-+ int pcache; /* pos */
-+ void *vcache; /* corresponding pointer for pos */
-+ int stripe; /* current stripe */
-+ struct list_head list; /* copy of stripe */
-+ int alloc_errors;
-+};
-+
-+/* deallocate copied stripe */
-+static void nf_free_stripe(struct list_head *list)
-+{
-+ struct ipt_netflow *cf, *tmp;
-+
-+ list_for_each_entry_safe(cf, tmp, list, flows_list) {
-+ kmem_cache_free(ipt_netflow_cachep, cf);
-+ }
-+ INIT_LIST_HEAD(list);
-+}
-+
-+/* quickly clone stripe into flows_dump_private then it can be walked slowly
-+ * and lockless */
-+static void __nf_copy_stripe(struct flows_dump_private *st, const struct list_head *list)
-+{
-+ const struct ipt_netflow *nf;
-+ struct ipt_netflow *cf;
-+
-+ nf_free_stripe(&st->list);
-+ list_for_each_entry(nf, list, flows_list) {
-+ cf = kmem_cache_alloc(ipt_netflow_cachep, GFP_ATOMIC);
-+ if (!cf) {
-+ st->alloc_errors++;
-+ continue;
-+ }
-+ memcpy(cf, nf, sizeof(*cf));
-+ list_add(&cf->flows_list, &st->list);
-+ }
-+}
-
--/* get first & next ipt_netflow list entry and lock it */
--static struct list_head *nf_get_first(int nstripe)
-+/* nstripe is desired stripe, in st->stripe will be recorded actual stripe used
-+ * (with empty stripes skipped), -1 is there is no valid stripes anymore,
-+ * return first element in stripe list or NULL */
-+static struct list_head *nf_get_stripe(struct flows_dump_private *st, int nstripe)
- {
-- /* no locking here since it's under global rwlock */
-+ read_lock_bh(&htable_rwlock);
- for (; nstripe < LOCK_COUNT; nstripe++) {
- struct stripe_entry *stripe = &htable_stripes[nstripe];
-
-+ spin_lock(&stripe->lock);
- if (!list_empty(&stripe->list)) {
-- seq_stripe = nstripe;
-- return stripe->list.next;
-+ st->stripe = nstripe;
-+ __nf_copy_stripe(st, &stripe->list);
-+ spin_unlock(&stripe->lock);
-+ read_unlock_bh(&htable_rwlock);
-+ return st->list.next;
- }
-+ spin_unlock(&stripe->lock);
- }
-- seq_stripe = -1;
-+ read_unlock_bh(&htable_rwlock);
-+ st->stripe = -1;
- return NULL;
- }
-
--static struct list_head *nf_get_next(struct list_head *head)
-+/* simply next element in flows list or NULL */
-+static struct list_head *nf_get_next(struct flows_dump_private *st, struct list_head *head)
- {
-- struct stripe_entry *stripe;
--
-- if (seq_stripe < 0)
-+ if (head == SEQ_START_TOKEN)
-+ return nf_get_stripe(st, 0);
-+ if (st->stripe < 0)
- return NULL;
-- stripe = &htable_stripes[seq_stripe];
-- head = head->next;
-- if (head != &stripe->list)
-- return head;
-- return nf_get_first(seq_stripe + 1);
-+ /* next element */
-+ if (!list_is_last(head, &st->list))
-+ return head->next;
-+ /* next bucket */
-+ return nf_get_stripe(st, st->stripe + 1);
- }
-
--static int seq_pcache;
--static void *seq_vcache;
-+/* seq_file could arbitrarily start/stop iteration as it feels need,
-+ * so, I try to cache things to (significantly) speed it up. */
- static void *flows_dump_seq_start(struct seq_file *seq, loff_t *pos)
- {
-+ struct flows_dump_private *st = seq->private;
- int ppos = *pos;
- struct list_head *lh;
-
- if (!ppos) {
-- seq_pcache = 0;
-- seq_vcache = nf_get_first(0);
-- return seq_vcache;
-- }
-- if (ppos >= seq_pcache) {
-- ppos -= seq_pcache;
-- lh = seq_vcache;
-- } else
-- lh = nf_get_first(0);
-+ /* first */
-+ st->pcache = 0;
-+ st->vcache = SEQ_START_TOKEN;
-+ return st->vcache;
-+ }
-+ if (ppos >= st->pcache) {
-+ /* can iterate forward */
-+ ppos -= st->pcache;
-+ lh = st->vcache;
-+ } else /* can't, start from 0 */
-+ lh = SEQ_START_TOKEN;
-+ /* iterate forward */
- while (ppos--)
-- lh = nf_get_next(lh);
-- seq_pcache = *pos;
-- seq_vcache = lh;
-- return seq_vcache;
-+ lh = nf_get_next(st, lh);
-+ st->pcache = *pos;
-+ st->vcache = lh;
-+ return st->vcache;
- }
-
- static void *flows_dump_seq_next(struct seq_file *seq, void *v, loff_t *pos)
- {
-- seq_pcache = ++*pos;
-- seq_vcache = nf_get_next((struct list_head *)v);
-- return seq_vcache;
-+ struct flows_dump_private *st = seq->private;
-+
-+ st->pcache = ++*pos;
-+ st->vcache = nf_get_next(st, (struct list_head *)v);
-+ return st->vcache;
- }
-
- static void flows_dump_seq_stop(struct seq_file *seq, void *v)
- {
- }
-
--static unsigned long dump_start; /* jiffies */
--static unsigned int dump_err;
- /* To view this: cat /sys/kernel/debug/netflow_dump */
- static int flows_dump_seq_show(struct seq_file *seq, void *v)
- {
-- struct ipt_netflow *nf = list_entry(v, struct ipt_netflow, flows_list);
-- long i_timeout = inactive_timeout * HZ;
-- long a_timeout = active_timeout * HZ;
-- int inactive = (jiffies - nf->nf_ts_last) >= i_timeout;
-- int active = active_needs_export(nf, a_timeout, dump_start);
-- u_int32_t hash = hash_netflow(&nf->tuple);
-+ struct flows_dump_private *st = seq->private;
-+ const long i_timeout = inactive_timeout * HZ;
-+ const long a_timeout = active_timeout * HZ;
-+ const struct ipt_netflow *nf;
-
-- if (seq_pcache == 0) {
-- unsigned int nr_flows = atomic_read(&ipt_netflow_count);
--
-- seq_printf(seq, "# Attention: netflow processing is disabled while dumping. (~%u flows)\n", nr_flows);
-+ if (v == SEQ_START_TOKEN) {
-+ seq_printf(seq, "# hash a dev:i,o"
-+#ifdef SNMP_RULES
-+ " snmp:i,o"
-+#endif
-+#ifdef ENABLE_MAC
-+ " mac:src,dst"
-+#endif
-+#ifdef ENABLE_VLAN
-+ " vlan"
-+#endif
-+#if defined(ENABLE_MAC) || defined(ENABLE_VLAN)
-+ " type"
-+#endif
-+ " proto src:ip,port dst:ip,port nexthop"
-+ " tos,tcpflags,options,tcpoptions"
-+ " packets bytes ts:first,last\n");
- return 0;
- }
-
-- seq_printf(seq, "%d %02x,%04x %02d",
-- seq_pcache,
-- seq_stripe,
-- hash,
-- inactive * 10 + active);
--#ifdef SNMP_RULES
-- seq_printf(seq, " %hd,%hd(%hd,%hd)",
-- nf->i_ifcr,
-- nf->o_ifcr,
-+ nf = list_entry(v, struct ipt_netflow, flows_list);
-+ seq_printf(seq, "%d %04x %x",
-+ st->pcache,
-+ hash_netflow(&nf->tuple),
-+ (!!inactive_needs_export(nf, i_timeout, jiffies)) |
-+ (active_needs_export(nf, a_timeout, jiffies) << 1));
-+ seq_printf(seq, " %hd,%hd",
- nf->tuple.i_ifc,
- nf->o_ifc);
--#else
-+#ifdef SNMP_RULES
- seq_printf(seq, " %hd,%hd",
-+ nf->i_ifcr,
-+ nf->o_ifcr,
- nf->tuple.i_ifc,
- nf->o_ifc);
- #endif
-@@ -1013,55 +1081,44 @@ static int flows_dump_seq_show(struct seq_file *seq, void *v)
- seq_printf(seq, " %pM,%pM", &nf->tuple.h_src, &nf->tuple.h_dst);
- #endif
- #ifdef ENABLE_VLAN
-- if (nf->tuple.tag1 || nf->tuple.tag2) {
-- seq_printf(seq, ",%d", ntohs(nf->tuple.tag1));
-- if (nf->tuple.tag2)
-- seq_printf(seq, ",%d", ntohs(nf->tuple.tag2));
-+ if (nf->tuple.tag[0]) {
-+ seq_printf(seq, " %d", ntohs(nf->tuple.tag[0]));
-+ if (nf->tuple.tag[1])
-+ seq_printf(seq, ",%d", ntohs(nf->tuple.tag[1]));
- }
- #endif
- #if defined(ENABLE_MAC) || defined(ENABLE_VLAN)
-- seq_printf(seq, " [%04x]", ntohs(nf->ethernetType));
-+ seq_printf(seq, " %04x", ntohs(nf->ethernetType));
- #endif
-- seq_printf(seq, " %u,%u ",
-- nf->tuple.l3proto,
-+ seq_printf(seq, " %u ",
- nf->tuple.protocol);
- if (nf->tuple.l3proto == AF_INET) {
-- seq_printf(seq, "%pI4n:%u,%pI4n:%u %pI4n",
-+ seq_printf(seq, "%pI4n,%u %pI4n,%u %pI4n",
- &nf->tuple.src,
- ntohs(nf->tuple.s_port),
- &nf->tuple.dst,
- ntohs(nf->tuple.d_port),
- &nf->nh);
-- /* sanity check */
-- if (nf->tuple.src.ip6[1] ||
-- nf->tuple.src.ip6[2] ||
-- nf->tuple.src.ip6[3])
-- seq_puts(seq, "error:src:garbage");
-- if (nf->tuple.dst.ip6[1] ||
-- nf->tuple.dst.ip6[2] ||
-- nf->tuple.dst.ip6[3])
-- seq_puts(seq, "error:dst:garbage");
- } else if (nf->tuple.l3proto == AF_INET6) {
-- seq_printf(seq, "%pI6c#%u,%pI6c#%u %pI6c",
-+ seq_printf(seq, "%pI6c,%u %pI6c,%u %pI6c",
- &nf->tuple.src,
- ntohs(nf->tuple.s_port),
- &nf->tuple.dst,
- ntohs(nf->tuple.d_port),
- &nf->nh);
- } else {
-- seq_puts(seq, "error:l3proto:unknown");
-+ seq_puts(seq, "?,? ?,? ?");
- }
- seq_printf(seq, " %x,%x,%x,%x",
- nf->tuple.tos,
- nf->tcp_flags,
- nf->options,
- nf->tcpoptions);
-- seq_printf(seq, " %d,%d %lu,%lu\n",
-+ seq_printf(seq, " %u %u %lu,%lu\n",
- nf->nr_packets,
- nf->nr_bytes,
- jiffies - nf->nf_ts_first,
-- jiffies - nf->nf_ts_last
-- );
-+ jiffies - nf->nf_ts_last);
-
- return 0;
- }
-@@ -1073,67 +1130,54 @@ static struct seq_operations flows_dump_seq_ops = {
- .stop = flows_dump_seq_stop,
- };
-
--static int flows_dump_open(struct inode *inode, struct file *file)
-+static int flows_seq_open(struct inode *inode, struct file *file)
- {
-- int ret;
-+ struct flows_dump_private *st;
- char *buf;
-+ const size_t size = 4 * PAGE_SIZE;
-
-- if (atomic_inc_return(&freeze) > 1) {
-- /* do not let concurrent dumps. */
-- atomic_dec(&freeze);
-- return -EAGAIN;
-- }
-- buf = kmalloc(KMALLOC_MAX_SIZE, GFP_KERNEL);
-- if (!buf) {
-- atomic_dec(&freeze);
-+ buf = kmalloc(size, GFP_KERNEL);
-+ if (!buf)
- return -ENOMEM;
-- }
-- pause_scan_worker();
-- synchronize_sched();
-- /* write_lock to be sure that softirq is finished */
-- write_lock(&htable_rwlock);
--
-- dump_start = jiffies;
-- dump_err = NETFLOW_STAT_READ(freeze_err);
-
-- ret = seq_open(file, &flows_dump_seq_ops);
-- if (ret) {
-- write_unlock(&htable_rwlock);
-- cont_scan_worker();
-+ st = __seq_open_private(file, &flows_dump_seq_ops, sizeof(struct flows_dump_private));
-+ if (!st) {
- kfree(buf);
-- atomic_dec(&freeze);
-- return ret;
-+ return -ENOMEM;
- }
-+ INIT_LIST_HEAD(&st->list);
-+ /* speed up seq interface with bigger buffer */
- ((struct seq_file *)file->private_data)->buf = buf;
-- ((struct seq_file *)file->private_data)->size = KMALLOC_MAX_SIZE;
-+ ((struct seq_file *)file->private_data)->size = size;
- return 0;
-
- }
--static int flows_dump_release(struct inode *inode, struct file *file)
-+static int flows_seq_release(struct inode *inode, struct file *file)
- {
-- seq_stripe = -1;
-- write_unlock(&htable_rwlock);
-- cont_scan_worker();
-- atomic_dec(&freeze);
-+ struct seq_file *seq = file->private_data;
-+ struct flows_dump_private *st = seq->private;
-
-- printk(KERN_INFO "ipt_NETFLOW: dump finished in %lu/%lu sec, dropped %u packets.\n",
-- jiffies - dump_start,
-- msecs_to_jiffies(1000),
-- NETFLOW_STAT_READ(freeze_err) - dump_err);
-- return seq_release(inode, file);
-+ nf_free_stripe(&st->list);
-+ if (st->alloc_errors)
-+ printk(KERN_INFO "ipt_NETFLOW: alloc_errors %d\n", st->alloc_errors);
-+ return seq_release_private(inode, file);
- }
-
--static const struct file_operations flows_dump_fops = {
-+static struct file_operations flows_seq_fops = {
- .owner = THIS_MODULE,
-- .open = flows_dump_open,
-+ .open = flows_seq_open,
- .read = seq_read,
- .llseek = seq_lseek,
-- .release = flows_dump_release,
-+ .release = flows_seq_release,
- };
--#endif /* ENABLE_DEBUGFS */
-+#endif /* CONFIG_PROC_FS */
-
- #ifdef ENABLE_PROMISC
--static int promisc_finish(struct sk_buff *skb)
-+static int promisc_finish(
-+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,1,0)
-+ struct sock *sk,
-+#endif
-+ struct sk_buff *skb)
- {
- /* don't pass to the routing */
- kfree_skb(skb);
-@@ -1145,16 +1189,8 @@ static int promisc4_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
- const struct iphdr *iph;
- u32 len;
-
-- /* what is not PACKET_OTHERHOST will be parsed at ip_rcv() */
-- if (skb->pkt_type != PACKET_OTHERHOST)
-- goto out;
--
-- NETFLOW_STAT_INC(pkt_promisc);
--
- /* clone skb and do basic IPv4 sanity checking and preparations
- * for L3, this is quick and dirty version of ip_rcv() */
-- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
-- goto drop;
- if (!pskb_may_pull(skb, sizeof(struct iphdr)))
- goto drop;
- iph = ip_hdr(skb);
-@@ -1176,10 +1212,10 @@ static int promisc4_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
- memset(IPCB(skb), 0, sizeof(struct inet_skb_parm));
- skb_orphan(skb);
-
-- return NF_HOOK(NFPROTO_IPV4, NF_INET_PRE_ROUTING, skb, dev, NULL, promisc_finish);
-+ return NF_HOOK_COMPAT(NFPROTO_IPV4, NF_INET_PRE_ROUTING, NULL,
-+ skb, dev, NULL, promisc_finish);
- drop:
- NETFLOW_STAT_INC(pkt_promisc_drop);
--out:
- kfree_skb(skb);
- return NET_RX_DROP;
- }
-@@ -1190,18 +1226,11 @@ static int promisc6_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
- u32 pkt_len;
- struct inet6_dev *idev;
-
-- /* what is not PACKET_OTHERHOST will be parsed at ipv6_rcv() */
-- if (skb->pkt_type != PACKET_OTHERHOST)
-- goto out;
--
-- NETFLOW_STAT_INC(pkt_promisc);
--
- /* quick and dirty version of ipv6_rcv(), basic sanity checking
- * and preparation of skb for later processing */
- rcu_read_lock();
- idev = __in6_dev_get(skb->dev);
-- if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL ||
-- !idev || unlikely(idev->cnf.disable_ipv6))
-+ if (!idev || unlikely(idev->cnf.disable_ipv6))
- goto drop;
- memset(IP6CB(skb), 0, sizeof(struct inet6_skb_parm));
- IP6CB(skb)->iif = skb_dst(skb) ? ip6_dst_idev(skb_dst(skb))->dev->ifindex : dev->ifindex;
-@@ -1252,22 +1281,127 @@ static int promisc6_rcv(struct sk_buff *skb, struct net_device *dev, struct pack
- rcu_read_unlock();
- skb_orphan(skb);
-
-- return NF_HOOK(NFPROTO_IPV6, NF_INET_PRE_ROUTING, skb, dev, NULL, promisc_finish);
-+ return NF_HOOK_COMPAT(NFPROTO_IPV6, NF_INET_PRE_ROUTING, NULL,
-+ skb, dev, NULL, promisc_finish);
- drop:
- rcu_read_unlock();
- NETFLOW_STAT_INC(pkt_promisc_drop);
--out:
- kfree_skb(skb);
- return NET_RX_DROP;
- }
-
--static struct packet_type promisc4_packet_type __read_mostly = {
-- .type = htons(ETH_P_IP),
-- .func = promisc4_rcv,
--};
--static struct packet_type promisc6_packet_type __read_mostly = {
-- .type = htons(ETH_P_IPV6),
-- .func = promisc6_rcv,
-+/* source is skb_network_protocol() and __vlan_get_protocol() */
-+static __be16 __skb_network_protocol(struct sk_buff *skb, int *depth)
-+{
-+ __be16 type = skb->protocol;
-+ unsigned int vlan_depth;
-+
-+ if (type == htons(ETH_P_TEB)) {
-+ struct ethhdr *eth;
-+
-+ if (unlikely(!pskb_may_pull(skb, sizeof(struct ethhdr))))
-+ return 0;
-+
-+ eth = (struct ethhdr *)skb_mac_header(skb);
-+ type = eth->h_proto;
-+ }
-+
-+ vlan_depth = skb->mac_len;
-+ if (type == htons(ETH_P_8021Q) || type == htons(ETH_P_8021AD)) {
-+ if (vlan_depth) {
-+ if (WARN_ON(vlan_depth < VLAN_HLEN))
-+ return 0;
-+ vlan_depth -= VLAN_HLEN;
-+ } else {
-+ vlan_depth = ETH_HLEN;
-+ }
-+ do {
-+ struct vlan_hdr *vh;
-+
-+ if (unlikely(!pskb_may_pull(skb, vlan_depth + VLAN_HLEN)))
-+ return 0;
-+
-+ vh = (struct vlan_hdr *)(skb->data + vlan_depth);
-+ type = vh->h_vlan_encapsulated_proto;
-+ vlan_depth += VLAN_HLEN;
-+ } while (type == htons(ETH_P_8021Q) ||
-+ type == htons(ETH_P_8021AD));
-+ }
-+
-+ *depth = vlan_depth;
-+
-+ return type;
-+}
-+
-+static int promisc_rcv(struct sk_buff *skb, struct net_device *dev, struct packet_type *pt, struct net_device *orig_dev)
-+{
-+ /* what is not PACKET_OTHERHOST will be processed normally */
-+ if (skb->pkt_type != PACKET_OTHERHOST)
-+ goto out;
-+
-+ NETFLOW_STAT_INC(pkt_promisc);
-+
-+ if ((skb = skb_share_check(skb, GFP_ATOMIC)) == NULL)
-+ goto drop;
-+
-+ /* Note about vlans:
-+ * - older kernels will pass raw packet;
-+ * - newer kernes (since 3.0) will have one vlan tag
-+ * physically stripped out of the packet, and it will
-+ * be saved into skb->vlan_tci. skb->protocol will be
-+ * untagged etherType. */
-+
-+ if (skb->protocol == cpu_to_be16(ETH_P_8021Q) ||
-+ skb->protocol == cpu_to_be16(ETH_P_8021AD)) {
-+ int vlan_depth = skb->mac_len;
-+
-+ skb_push(skb, skb->data - skb_mac_header(skb));
-+ skb->protocol = __skb_network_protocol(skb, &vlan_depth);
-+ skb_pull(skb, vlan_depth);
-+
-+ skb_reset_network_header(skb);
-+ skb_reset_mac_len(skb);
-+ }
-+# ifdef PROMISC_MPLS
-+ if (eth_p_mpls(skb->protocol)) {
-+ size_t stack_len = 0;
-+ const struct mpls_label *mpls;
-+
-+ do {
-+ stack_len += MPLS_HLEN;
-+ if (unlikely(!pskb_may_pull(skb, stack_len)))
-+ goto drop;
-+ mpls = (struct mpls_label *)(skb->data + stack_len - MPLS_HLEN);
-+ } while (!(mpls->entry & htonl(MPLS_LS_S_MASK)));
-+
-+ skb_pull(skb, stack_len);
-+ skb_reset_network_header(skb);
-+
-+ if (!pskb_may_pull(skb, 1))
-+ goto drop;
-+ switch (ip_hdr(skb)->version) {
-+ case 4: skb->protocol = htons(ETH_P_IP); break;
-+ case 6: skb->protocol = htons(ETH_P_IPV6); break;
-+ default: goto drop;
-+ }
-+ }
-+# endif
-+ switch (skb->protocol) {
-+ case htons(ETH_P_IP):
-+ return promisc4_rcv(skb, dev, pt, orig_dev);
-+ case htons(ETH_P_IPV6):
-+ return promisc6_rcv(skb, dev, pt, orig_dev);
-+ }
-+drop:
-+ NETFLOW_STAT_INC(pkt_promisc_drop);
-+out:
-+ kfree_skb(skb);
-+ return 0;
-+}
-+
-+static struct packet_type promisc_packet_type __read_mostly = {
-+ .type = htons(ETH_P_ALL),
-+ .func = promisc_rcv,
- };
-
- /* should not have promisc passed as parameter */
-@@ -1277,13 +1411,10 @@ static int switch_promisc(int newpromisc)
- mutex_lock(&promisc_lock);
- if (newpromisc == promisc)
- goto unlock;
-- if (newpromisc) {
-- dev_add_pack(&promisc4_packet_type);
-- dev_add_pack(&promisc6_packet_type);
-- } else {
-- dev_remove_pack(&promisc4_packet_type);
-- dev_remove_pack(&promisc6_packet_type);
-- }
-+ if (newpromisc)
-+ dev_add_pack(&promisc_packet_type);
-+ else
-+ dev_remove_pack(&promisc_packet_type);
- printk(KERN_INFO "ipt_NETFLOW: promisc hack is %s\n",
- newpromisc? "enabled" : "disabled");
- promisc = newpromisc;
-@@ -1294,21 +1425,6 @@ unlock:
- #endif
-
- #ifdef CONFIG_SYSCTL
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,32)
--#define BEFORE2632(x,y) x,y
--#else /* since 2.6.32 */
--#define BEFORE2632(x,y)
--#endif
--
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,17,0)
--#define ctl_table struct ctl_table
--#endif
--
--#ifndef CONFIG_GRKERNSEC
--#define ctl_table_no_const ctl_table
--#endif
--
- /* sysctl /proc/sys/net/netflow */
- static int hsize_procctl(ctl_table *ctl, int write, BEFORE2632(struct file *filp,)
- void __user *buffer, size_t *lenp, loff_t *fpos)
-@@ -1753,30 +1869,25 @@ static void sk_error_report(struct sock *sk)
- return;
- }
-
--static struct socket *usock_open_sock(const __be32 ipaddr, const unsigned short port, void *u)
-+static struct socket *usock_open_sock(const struct sockaddr_storage *addr, void *user_data)
- {
-- struct sockaddr_in sin;
- struct socket *sock;
- int error;
-
-- if ((error = sock_create_kern(PF_INET, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
-+ if ((error = sock_create_kern(addr->ss_family, SOCK_DGRAM, IPPROTO_UDP, &sock)) < 0) {
- printk(KERN_ERR "ipt_NETFLOW: sock_create_kern error %d\n", -error);
- return NULL;
- }
- sock->sk->sk_allocation = GFP_ATOMIC;
- sock->sk->sk_prot->unhash(sock->sk); /* hidden from input */
- sock->sk->sk_error_report = &sk_error_report; /* clear ECONNREFUSED */
-- sock->sk->sk_user_data = u;
-+ sock->sk->sk_user_data = user_data; /* usock */
- if (sndbuf)
- sock->sk->sk_sndbuf = sndbuf;
- else
- sndbuf = sock->sk->sk_sndbuf;
-- memset(&sin, 0, sizeof(sin));
-- sin.sin_family = AF_INET;
-- sin.sin_addr.s_addr = htonl(ipaddr);
-- sin.sin_port = htons(port);
-- if ((error = sock->ops->connect(sock, (struct sockaddr *)&sin,
-- sizeof(sin), 0)) < 0) {
-+ error = sock->ops->connect(sock, (struct sockaddr *)addr, sizeof(*addr), 0);
-+ if (error < 0) {
- printk(KERN_ERR "ipt_NETFLOW: error connecting UDP socket %d,"
- " don't worry, will try reconnect later.\n", -error);
- /* ENETUNREACH when no interfaces */
-@@ -1788,18 +1899,16 @@ static struct socket *usock_open_sock(const __be32 ipaddr, const unsigned short
-
- static void usock_connect(struct ipt_netflow_sock *usock, const int sendmsg)
- {
-- usock->sock = usock_open_sock(usock->ipaddr, usock->port, usock);
-+ usock->sock = usock_open_sock(&usock->addr, usock);
- if (usock->sock) {
- if (sendmsg || debug)
-- printk(KERN_INFO "ipt_NETFLOW: connected %u.%u.%u.%u:%u\n",
-- HIPQUAD(usock->ipaddr),
-- usock->port);
-+ printk(KERN_INFO "ipt_NETFLOW: connected %s\n",
-+ print_sockaddr(&usock->addr));
- } else {
- usock->err_connect++;
- if (debug)
-- printk(KERN_INFO "ipt_NETFLOW: connect to %u.%u.%u.%u:%u failed%s.\n",
-- HIPQUAD(usock->ipaddr),
-- usock->port,
-+ printk(KERN_INFO "ipt_NETFLOW: connect to %s failed%s.\n",
-+ print_sockaddr(&usock->addr),
- (sendmsg)? " (pdu lost)" : "");
- }
- atomic_set(&usock->wmem_peak, 0);
-@@ -1888,9 +1997,8 @@ static void netflow_sendmsg(void *buffer, const int len)
-
- static void usock_close_free(struct ipt_netflow_sock *usock)
- {
-- printk(KERN_INFO "ipt_NETFLOW: removed destination %u.%u.%u.%u:%u\n",
-- HIPQUAD(usock->ipaddr),
-- usock->port);
-+ printk(KERN_INFO "ipt_NETFLOW: removed destination %s\n",
-+ print_sockaddr(&usock->addr));
- usock_close(usock);
- vfree(usock);
- }
-@@ -1917,17 +2025,15 @@ static void add_usock(struct ipt_netflow_sock *usock)
- mutex_lock(&sock_lock);
- /* don't need duplicated sockets */
- list_for_each_entry(sk, &usock_list, list) {
-- if (sk->ipaddr == usock->ipaddr &&
-- sk->port == usock->port) {
-+ if (sockaddr_cmp(&sk->addr, &usock->addr)) {
- mutex_unlock(&sock_lock);
- usock_close_free(usock);
- return;
- }
- }
- list_add_tail(&usock->list, &usock_list);
-- printk(KERN_INFO "ipt_NETFLOW: added destination %u.%u.%u.%u:%u%s\n",
-- HIPQUAD(usock->ipaddr),
-- usock->port,
-+ printk(KERN_INFO "ipt_NETFLOW: added destination %s%s\n",
-+ print_sockaddr(&usock->addr),
- (!usock->sock)? " (unconnected)" : "");
- mutex_unlock(&sock_lock);
- }
-@@ -2105,33 +2211,76 @@ static inline int resolve_snmp(const struct net_device *ifc)
- }
- #endif /* SNMP_RULES */
-
-+/* count how much character c is in the string */
-+static size_t strncount(const char *s, size_t count, int c)
-+{
-+ size_t amount = 0;
-+
-+ for (; count-- && *s != '\0'; ++s)
-+ if (*s == (char)c)
-+ ++amount;
-+ return amount;
-+}
-+
- #define SEPARATORS " ,;\t\n"
--static int add_destinations(char *ptr)
-+static int add_destinations(const char *ptr)
- {
-- while (ptr) {
-- unsigned char ip[4];
-- unsigned short port;
-+ int len;
-
-- ptr += strspn(ptr, SEPARATORS);
-+ for (; ptr; ptr += len) {
-+ struct sockaddr_storage ss;
-+ struct ipt_netflow_sock *usock;
-+ const char *end;
-+ int succ = 0;
-
-- if (sscanf(ptr, "%hhu.%hhu.%hhu.%hhu:%hu",
-- ip, ip + 1, ip + 2, ip + 3, &port) == 5) {
-- struct ipt_netflow_sock *usock;
-+ /* skip initial separators */
-+ ptr += strspn(ptr, SEPARATORS);
-
-- if (!(usock = vmalloc(sizeof(*usock)))) {
-- printk(KERN_ERR "ipt_NETFLOW: can't vmalloc socket\n");
-- return -ENOMEM;
-+ len = strcspn(ptr, SEPARATORS);
-+ if (!len)
-+ break;
-+ memset(&ss, 0, sizeof(ss));
-+
-+ if (strncount(ptr, len, ':') >= 2) {
-+ struct sockaddr_in6 *sin6 = (struct sockaddr_in6 *)&ss;
-+ const char *c = ptr;
-+ int clen = len;
-+
-+ sin6->sin6_family = AF_INET6;
-+ sin6->sin6_port = htons(2055);
-+ if (*c == '[') {
-+ ++c;
-+ --clen;
- }
-+ succ = in6_pton(c, clen, (u8 *)&sin6->sin6_addr, -1, &end);
-+ if (succ && *ptr == '[' && *end == ']')
-+ ++end;
-+ if (succ &&
-+ (*end == ':' || *end == '.' || *end == 'p' || *end == '#'))
-+ sin6->sin6_port = htons(simple_strtoul(++end, NULL, 0));
-+ } else {
-+ struct sockaddr_in *sin = (struct sockaddr_in *)&ss;
-
-- memset(usock, 0, sizeof(*usock));
-- usock->ipaddr = ntohl(*(__be32 *)ip);
-- usock->port = port;
-- usock_connect(usock, 0);
-- add_usock(usock);
-- } else
-- break;
-+ sin->sin_family = AF_INET;
-+ sin->sin_port = htons(2055);
-+ succ = in4_pton(ptr, len, (u8 *)&sin->sin_addr, -1, &end);
-+ if (succ && *end == ':')
-+ sin->sin_port = htons(simple_strtoul(++end, NULL, 0));
-+ }
-+ if (!succ) {
-+ printk(KERN_ERR "ipt_NETFLOW: can't parse destination: %.*s\n",
-+ len, ptr);
-+ continue;
-+ }
-
-- ptr = strpbrk(ptr, SEPARATORS);
-+ if (!(usock = vmalloc(sizeof(*usock)))) {
-+ printk(KERN_ERR "ipt_NETFLOW: can't vmalloc socket\n");
-+ return -ENOMEM;
-+ }
-+ memset(usock, 0, sizeof(*usock));
-+ usock->addr = ss;
-+ usock_connect(usock, 0);
-+ add_usock(usock);
- }
- return 0;
- }
-@@ -2246,12 +2395,7 @@ ipt_netflow_find(const struct ipt_netflow_tuple *tuple, const unsigned int hash)
- {
- struct ipt_netflow *nf;
- #if LINUX_VERSION_CODE < KERNEL_VERSION(3,9,0)
--#define compat_hlist_for_each_entry hlist_for_each_entry
--#define compat_hlist_for_each_entry_safe hlist_for_each_entry_safe
- struct hlist_node *pos;
--#else /* since 3.9.0 */
--#define compat_hlist_for_each_entry(a,pos,c,d) hlist_for_each_entry(a,c,d)
--#define compat_hlist_for_each_entry_safe(a,pos,c,d,e) hlist_for_each_entry_safe(a,c,d,e)
- #endif
-
- compat_hlist_for_each_entry(nf, pos, &htable[hash], hlist) {
-@@ -2529,7 +2673,7 @@ static inline void pdu_rewind_space(const size_t size)
- /* allocate data space in pdu, or export (reallocate) and fail. */
- static inline unsigned char *pdu_alloc_fail_export(const size_t size)
- {
-- if (!pdu_have_space(size)) {
-+ if (unlikely(!pdu_have_space(size))) {
- netflow_export_pdu();
- return NULL;
- }
-@@ -2585,6 +2729,7 @@ struct base_template {
- #define BTPL_DIRECTION 0x00200000 /* flowDirection */
- #define BTPL_SAMPLERID 0x00400000 /* samplerId (v9) */
- #define BTPL_SELECTORID 0x00800000 /* selectorId (IPFIX) */
-+#define BTPL_MPLS 0x01000000 /* MPLS stack */
- #define BTPL_OPTION 0x80000000 /* Options Template */
- #define BTPL_MAX 32
- /* Options Templates */
-@@ -2604,6 +2749,10 @@ static struct base_template template_base_9 = {
- .types = {
- INPUT_SNMP,
- OUTPUT_SNMP,
-+#ifdef ENABLE_PHYSDEV
-+ ingressPhysicalInterface,
-+ egressPhysicalInterface,
-+#endif
- IN_PKTS,
- IN_BYTES,
- FIRST_SWITCHED,
-@@ -2617,12 +2766,17 @@ static struct base_template template_base_ipfix = {
- .types = {
- ingressInterface,
- egressInterface,
-+#ifdef ENABLE_PHYSDEV
-+ ingressPhysicalInterface,
-+ egressPhysicalInterface,
-+#endif
- packetDeltaCount,
- octetDeltaCount,
- flowStartMilliseconds,
- flowEndMilliseconds,
- protocolIdentifier,
- ipClassOfService,
-+ flowEndReason,
- 0
- }
- };
-@@ -2660,6 +2814,27 @@ static struct base_template template_vlan_inner = {
- }
- };
- #endif
-+#ifdef MPLS_DEPTH
-+static struct base_template template_mpls = {
-+ .types = {
-+ mplsTopLabelTTL,
-+ /* do not just add element here, becasue this array
-+ * is truncated in ipt_netflow_init() */
-+#define MPLS_LABELS_BASE_INDEX 1
-+ MPLS_LABEL_1,
-+ MPLS_LABEL_2,
-+ MPLS_LABEL_3,
-+ MPLS_LABEL_4,
-+ MPLS_LABEL_5,
-+ MPLS_LABEL_6,
-+ MPLS_LABEL_7,
-+ MPLS_LABEL_8,
-+ MPLS_LABEL_9,
-+ MPLS_LABEL_10,
-+ 0
-+ }
-+};
-+#endif
- #ifdef ENABLE_DIRECTION
- static struct base_template template_direction = {
- .types = { DIRECTION, 0 }
-@@ -3026,6 +3201,10 @@ static struct data_template *get_template(const unsigned int tmask)
- if (tmask & BTPL_ETHERTYPE)
- tlist[tnum++] = &template_ethertype;
- #endif
-+#ifdef MPLS_DEPTH
-+ if (tmask & BTPL_MPLS)
-+ tlist[tnum++] = &template_mpls;
-+#endif
- #ifdef ENABLE_DIRECTION
- if (tmask & BTPL_DIRECTION)
- tlist[tnum++] = &template_direction;
-@@ -3176,23 +3355,6 @@ static void pdu_add_template(struct data_template *tpl)
- pdu_tpl_records++;
- }
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
--static inline s64 portable_ktime_to_ms(const ktime_t kt)
--{
-- struct timeval tv = ktime_to_timeval(kt);
-- return (s64) tv.tv_sec * MSEC_PER_SEC + tv.tv_usec / USEC_PER_MSEC;
--}
--#define ktime_to_ms portable_ktime_to_ms
--#endif
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
--static inline s64 portable_ktime_to_us(const ktime_t kt)
--{
-- struct timeval tv = ktime_to_timeval(kt);
-- return (s64) tv.tv_sec * USEC_PER_SEC + tv.tv_usec;
--}
--#define ktime_to_us portable_ktime_to_us
--#endif
--
- #ifdef ENABLE_DIRECTION
- static inline __u8 hook2dir(const __u8 hooknum)
- {
-@@ -3209,21 +3371,6 @@ static inline __u8 hook2dir(const __u8 hooknum)
- }
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
--static inline void put_unaligned_be16(u16 val, void *p)
--{
-- put_unaligned(cpu_to_be16(val), (__be16 *)p);
--}
--static inline void put_unaligned_be32(u32 val, void *p)
--{
-- put_unaligned(cpu_to_be32(val), (__be32 *)p);
--}
--static inline void put_unaligned_be64(u64 val, void *p)
--{
-- put_unaligned(cpu_to_be64(val), (__be64 *)p);
--}
--#endif
--
- static inline void put_unaligned_be24(u32 val, unsigned char *p)
- {
- *p++ = val >> 16;
-@@ -3260,9 +3407,6 @@ static inline s64 jiffies_to_ms_abs(unsigned long j)
- return jiffies_base.ms + (s64)jiffies_to_msecs(-jdiff);
- }
-
--#ifndef WARN_ONCE
--#define WARN_ONCE(x,fmt...) ({ if (x) printk(KERN_WARNING fmt); })
--#endif
- typedef struct in6_addr in6_t;
- /* encode one field (data records only) */
- static inline void add_tpl_field(__u8 *ptr, const int type, const struct ipt_netflow *nf)
-@@ -3286,14 +3430,20 @@ static inline void add_tpl_field(__u8 *ptr, const int type, const struct ipt_net
- case INPUT_SNMP: put_unaligned_be16(nf->tuple.i_ifc, ptr); break;
- case OUTPUT_SNMP: put_unaligned_be16(nf->o_ifc, ptr); break;
- #endif
-+#ifdef ENABLE_PHYSDEV
-+ case ingressPhysicalInterface:
-+ put_unaligned_be16(nf->i_ifphys, ptr); break;
-+ case egressPhysicalInterface:
-+ put_unaligned_be16(nf->o_ifphys, ptr); break;
-+#endif
- #ifdef ENABLE_VLAN
- #define EXTRACT_VLAN_PRIO(tag) ((ntohs(tag) & VLAN_PRIO_MASK) >> VLAN_PRIO_SHIFT)
- case SRC_VLAN:
-- case dot1qVlanId: put_unaligned(nf->tuple.tag1 & htons(VLAN_VID_MASK), (__be16 *)ptr); break;
-- case dot1qPriority: *ptr = EXTRACT_VLAN_PRIO(nf->tuple.tag1); break;
-+ case dot1qVlanId: put_unaligned(nf->tuple.tag[0] & htons(VLAN_VID_MASK), (__be16 *)ptr); break;
-+ case dot1qPriority: *ptr = EXTRACT_VLAN_PRIO(nf->tuple.tag[0]); break;
- case dot1qCustomerVlanId:
-- put_unaligned(nf->tuple.tag2 & htons(VLAN_VID_MASK), (__be16 *)ptr); break;
-- case dot1qCustomerPriority: *ptr = EXTRACT_VLAN_PRIO(nf->tuple.tag2); break;
-+ put_unaligned(nf->tuple.tag[1] & htons(VLAN_VID_MASK), (__be16 *)ptr); break;
-+ case dot1qCustomerPriority: *ptr = EXTRACT_VLAN_PRIO(nf->tuple.tag[1]); break;
- #endif
- #if defined(ENABLE_MAC) || defined(ENABLE_VLAN)
- case ethernetType: put_unaligned(nf->ethernetType, (__be16 *)ptr); break;
-@@ -3302,6 +3452,21 @@ static inline void add_tpl_field(__u8 *ptr, const int type, const struct ipt_net
- case destinationMacAddress: memcpy(ptr, &nf->tuple.h_dst, ETH_ALEN); break;
- case sourceMacAddress: memcpy(ptr, &nf->tuple.h_src, ETH_ALEN); break;
- #endif
-+#ifdef MPLS_DEPTH
-+ case MPLS_LABEL_1: memcpy(ptr, &nf->tuple.mpls[0], 3); break;
-+ case MPLS_LABEL_2: memcpy(ptr, &nf->tuple.mpls[1], 3); break;
-+ case MPLS_LABEL_3: memcpy(ptr, &nf->tuple.mpls[2], 3); break;
-+# if MPLS_DEPTH > 3
-+ case MPLS_LABEL_4: memcpy(ptr, &nf->tuple.mpls[3], 3); break;
-+ case MPLS_LABEL_5: memcpy(ptr, &nf->tuple.mpls[4], 3); break;
-+ case MPLS_LABEL_6: memcpy(ptr, &nf->tuple.mpls[5], 3); break;
-+ case MPLS_LABEL_7: memcpy(ptr, &nf->tuple.mpls[6], 3); break;
-+ case MPLS_LABEL_8: memcpy(ptr, &nf->tuple.mpls[7], 3); break;
-+ case MPLS_LABEL_9: memcpy(ptr, &nf->tuple.mpls[8], 3); break;
-+ case MPLS_LABEL_10: memcpy(ptr, &nf->tuple.mpls[9], 3); break;
-+# endif
-+ case mplsTopLabelTTL: *ptr = ntohl(nf->tuple.mpls[0]); break;
-+#endif
- #ifdef ENABLE_DIRECTION
- case DIRECTION: *ptr = hook2dir(nf->hooknumx - 1); break;
- #endif
-@@ -3321,6 +3486,7 @@ static inline void add_tpl_field(__u8 *ptr, const int type, const struct ipt_net
- case icmpTypeCodeIPv4: /*FALLTHROUGH*/
- case icmpTypeCodeIPv6: put_unaligned(nf->tuple.d_port, (__be16 *)ptr); break;
- case MUL_IGMP_TYPE: *ptr = nf->tuple.d_port; break;
-+ case flowEndReason: *ptr = nf->flowEndReason; break;
- #ifdef CONFIG_NF_NAT_NEEDED
- case postNATSourceIPv4Address: put_unaligned(nf->nat->post.s_addr, (__be32 *)ptr); break;
- case postNATDestinationIPv4Address: put_unaligned(nf->nat->post.d_addr, (__be32 *)ptr); break;
-@@ -3363,18 +3529,6 @@ static inline unsigned long timeout_rate_j(void)
- return t_rate_j;
- }
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,20)
--#define IPPROTO_UDPLITE 136
--#endif
--
--#ifndef time_is_before_jiffies
--#define time_is_before_jiffies(a) time_after(jiffies, a)
--#endif
--#ifndef time_is_after_jiffies
--#define time_is_after_jiffies(a) time_before(jiffies, a)
--#endif
--
--
- /* return buffer where to write records data */
- static unsigned char *alloc_record_tpl(struct data_template *tpl)
- {
-@@ -3382,9 +3536,9 @@ static unsigned char *alloc_record_tpl(struct data_template *tpl)
-
- /* If previous write was to the same template and there is room, then we just add new record,
- * otherwise we (re)allocate flowset (and/or whole pdu). */
-- if (unlikely(!pdu_flowset ||
-+ if (!pdu_flowset ||
- pdu_flowset->flowset_id != tpl->template_id_n ||
-- !(ptr = pdu_alloc_fail_export(tpl->rec_size)))) {
-+ !(ptr = pdu_alloc_fail_export(tpl->rec_size))) {
-
- /* if there was previous data template we should pad it to 4 bytes */
- if (pdu_flowset) {
-@@ -3427,18 +3581,6 @@ static unsigned char *alloc_record_key(const unsigned int t_key, struct data_tem
- return alloc_record_tpl(tpl);
- }
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(3,14,0)
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
--#define prandom_u32 get_random_int
--#elif LINUX_VERSION_CODE < KERNEL_VERSION(3,8,0)
--#define prandom_u32 random32
--#endif
--static inline u32 prandom_u32_max(u32 ep_ro)
--{
-- return (u32)(((u64) prandom_u32() * ep_ro) >> 32);
--}
--#endif
--
- static void netflow_export_flow_tpl(struct ipt_netflow *nf)
- {
- unsigned char *ptr;
-@@ -3497,12 +3639,12 @@ static void netflow_export_flow_tpl(struct ipt_netflow *nf)
- tpl_mask |= BTPL_MAC;
- #endif
- #ifdef ENABLE_VLAN
-- if (nf->tuple.tag1) {
-+ if (nf->tuple.tag[0]) {
- if (protocol == 9)
- tpl_mask |= BTPL_VLAN9;
- else {
- tpl_mask |= BTPL_VLANX;
-- if (nf->tuple.tag2)
-+ if (nf->tuple.tag[1])
- tpl_mask |= BTPL_VLANI;
- }
- }
-@@ -3511,6 +3653,10 @@ static void netflow_export_flow_tpl(struct ipt_netflow *nf)
- if (nf->ethernetType)
- tpl_mask |= BTPL_ETHERTYPE;
- #endif
-+#ifdef MPLS_DEPTH
-+ if (nf->tuple.mpls[0])
-+ tpl_mask |= BTPL_MPLS;
-+#endif
- #ifdef ENABLE_DIRECTION
- if (nf->hooknumx)
- tpl_mask |= BTPL_DIRECTION;
-@@ -3657,13 +3803,6 @@ static inline void export_stat(const unsigned int tpl_mask)
- export_stat_st(tpl_mask, NULL);
- }
-
--#ifndef min_not_zero
--#define min_not_zero(x, y) ({ \
-- typeof(x) __x = (x); \
-- typeof(y) __y = (y); \
-- __x == 0 ? __y : ((__y == 0) ? __x : min(__x, __y)); })
--#endif
--
- static void netflow_export_stats(void)
- {
- struct ipt_netflow_stat t = { 0 };
-@@ -3748,20 +3887,6 @@ static void export_sampler_parameters(void)
- }
- #endif
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(3,2,0)
--int __ethtool_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
--{
-- ASSERT_RTNL();
--
-- if (!dev->ethtool_ops->get_settings)
-- return -EOPNOTSUPP;
--
-- memset(cmd, 0, sizeof(struct ethtool_cmd));
-- cmd->cmd = ETHTOOL_GSET;
-- return dev->ethtool_ops->get_settings(dev, cmd);
--}
--#endif
--
- static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *dev)
- {
- struct ethtool_drvinfo info = { 0 };
-@@ -3774,8 +3899,8 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d
- return 0;
- if (ops->begin) {
- /* was not called before __ethtool_get_settings() though */
-- if (ops->begin(dev) < 0);
-- return 0;
-+ if (ops->begin(dev) < 0)
-+ return 0;
- }
-
- /* driver name */
-@@ -3792,13 +3917,13 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d
- if (!n || len <= 1) /* have room for separator too */
- goto ret;
-
-- /* append basic parameters: speed and port */
-- if (!__ethtool_get_settings(dev, &ecmd)) {
-+ /* only get_settings for running devices to not trigger link negotiation */
-+ if (dev->flags & IFF_UP &&
-+ dev->flags & IFF_RUNNING &&
-+ !__ethtool_get_settings(dev, &ecmd)) {
- char *s, *p;
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,27)
--#define ethtool_cmd_speed(x) (x)->speed
--#endif
-+ /* append basic parameters: speed and port */
- switch (ethtool_cmd_speed(&ecmd)) {
- case SPEED_10000: s = "10Gb"; break;
- case SPEED_2500: s = "2.5Gb"; break;
-@@ -3827,14 +3952,6 @@ ret:
- return size - len;
- }
-
--#ifndef ARPHRD_PHONET
--#define ARPHRD_PHONET 820
--#define ARPHRD_PHONET_PIPE 821
--#endif
--#ifndef ARPHRD_IEEE802154
--#define ARPHRD_IEEE802154 804
--#endif
--
- static const unsigned short netdev_type[] =
- {ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_AX25,
- ARPHRD_IEEE802, ARPHRD_ARCNET,
-@@ -3939,13 +4056,6 @@ static void export_dev(struct net_device *dev)
- pdu_ts_mod = jiffies;
- }
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,22)
--#define for_each_netdev_ns(net, dev) for (dev = dev_base; dev; dev = dev->next)
--#elif LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
--#define for_each_netdev_ns(net, d) for_each_netdev(d)
--#else
--#define for_each_netdev_ns(net, d) for_each_netdev(net, d)
--#endif
- static void export_ifnames(void)
- {
- struct net_device *dev;
-@@ -4041,14 +4151,40 @@ static void export_nat_event(struct nat_event *nel)
- }
- #endif /* CONFIG_NF_NAT_NEEDED */
-
--static inline int active_needs_export(const struct ipt_netflow *nf, const long a_timeout, const unsigned long jiff)
-+static inline int active_needs_export(const struct ipt_netflow *nf, const long a_timeout,
-+ const unsigned long j)
-+{
-+ return ((j - nf->nf_ts_first) > a_timeout) ||
-+ nf->nr_bytes >= FLOW_FULL_WATERMARK;
-+}
-+
-+/* return flowEndReason (rfc5102) */
-+/* i_timeout == 0 is flush */
-+static inline int inactive_needs_export(const struct ipt_netflow *nf, const long i_timeout,
-+ const unsigned long j)
- {
-- /* active too long, finishing, or having too much bytes */
-- return ((jiff - nf->nf_ts_first) > a_timeout) ||
-- (nf->tuple.protocol == IPPROTO_TCP &&
-- (nf->tcp_flags & TCP_FIN_RST) &&
-- (jiff - nf->nf_ts_last) > (1 * HZ)) ||
-- nf->nr_bytes >= FLOW_FULL_WATERMARK;
-+ if (likely(i_timeout)) {
-+ if (unlikely((j - nf->nf_ts_last) > i_timeout)) {
-+ if (nf->tuple.protocol == IPPROTO_TCP &&
-+ (nf->tcp_flags & TCP_FIN_RST))
-+ return 0x03; /* end of Flow detected */
-+ else
-+ return 0x01; /* idle timeout */
-+ } else
-+ return 0;
-+ } else
-+ return 0x04; /* forced end */
-+}
-+
-+/* helper which also record to nf->flowEndReason */
-+static inline int needs_export_rec(struct ipt_netflow *nf, const long i_timeout,
-+ const long a_timeout, const unsigned long j)
-+{
-+ int reason = inactive_needs_export(nf, i_timeout, j);
-+
-+ if (!reason && active_needs_export(nf, a_timeout, j))
-+ reason = 0x02; /* active timeout or just active flow */
-+ return (nf->flowEndReason = reason);
- }
-
- /* could be called with zero to flush cache and pdu */
-@@ -4056,13 +4192,12 @@ static inline int active_needs_export(const struct ipt_netflow *nf, const long a
- /* return number of pdus sent */
- static int netflow_scan_and_export(const int flush)
- {
-- long i_timeout = inactive_timeout * HZ;
-+ const long i_timeout = flush? 0 : inactive_timeout * HZ;
-+ const long a_timeout = active_timeout * HZ;
- #ifdef HAVE_LLIST
- struct llist_node *node;
--#else
-- long a_timeout = active_timeout * HZ;
- #endif
-- int pdu_c = pdu_count;
-+ const int pdu_c = pdu_count;
- LIST_HEAD(export_list);
- struct ipt_netflow *nf, *tmp;
- int i;
-@@ -4070,9 +4205,6 @@ static int netflow_scan_and_export(const int flush)
- unsigned char mode;
- #endif
-
-- if (flush)
-- i_timeout = 0;
--
- if (protocol >= 9) {
- netflow_export_stats();
- #ifdef ENABLE_SAMPLER
-@@ -4091,14 +4223,7 @@ static int netflow_scan_and_export(const int flush)
- }
- list_for_each_entry_safe_reverse(nf, tmp, &stripe->list, flows_list) {
- ++wk_count;
-- if (((jiffies - nf->nf_ts_last) >= i_timeout)
--#ifdef HAVE_LLIST
-- /* exportable actives already go into export_llist,
-- * thus this check is redundant. */
--#else
-- || active_needs_export(nf, a_timeout, jiffies)
--#endif
-- ) {
-+ if (needs_export_rec(nf, i_timeout, a_timeout, jiffies)) {
- hlist_del(&nf->hlist);
- list_del(&nf->flows_list);
- list_add(&nf->flows_list, &export_list);
-@@ -4387,13 +4512,6 @@ netflow_target_check(const struct xt_tgchk_param *par)
- if (strcmp("nat", tablename) == 0) {
- /* In the nat table we only see single packet per flow, which is useless. */
- printk(KERN_ERR "%s target: is not valid in %s table\n", target->name, tablename);
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
--#define CHECK_FAIL 0
--#define CHECK_OK 1
--#else
--#define CHECK_FAIL -EINVAL
--#define CHECK_OK 0
--#endif
- return CHECK_FAIL;
- }
- if (target->family == AF_INET6 && protocol == 5) {
-@@ -4404,9 +4522,6 @@ netflow_target_check(const struct xt_tgchk_param *par)
- }
-
- #define SetXBit(x) (0x8000 >> (x)) /* Proper bit for htons later. */
--#ifndef IPPROTO_MH
--#define IPPROTO_MH 135
--#endif
- static inline __u16 observed_hdrs(const __u8 currenthdr)
- {
- switch (currenthdr) {
-@@ -4537,69 +4652,80 @@ static inline __u32 tcp_options(const struct sk_buff *skb, const unsigned int pt
- return ret;
- }
-
--#ifdef ENABLE_VLAN
--/* double tagged header */
--struct vlan_ethhdr2 {
-- unsigned char h_dest[ETH_ALEN];
-- unsigned char h_source[ETH_ALEN];
-- __be16 h_vlan_proto;
-- __be16 h_vlan_TCI;
-- __be16 h2_vlan_proto;
-- __be16 h2_vlan_TCI;
-- __be16 h2_vlan_encapsulated_proto;
--};
--static inline struct vlan_ethhdr2 *vlan_eth_hdr2(const struct sk_buff *skb)
-+/* check if data region is in header boundary */
-+inline static int skb_in_header(const struct sk_buff *skb, const void *ptr, size_t off)
- {
-- return (struct vlan_ethhdr2 *)skb_mac_header(skb);
-+ return ((unsigned char *)ptr + off) <= skb->data;
- }
--#define VLAN_ETH_H2LEN (VLAN_ETH_HLEN + 4)
--#ifndef ETH_P_8021AD
--#define ETH_P_8021AD 0x88A8 /* 802.1ad Service VLAN */
--#endif
--#ifndef ETH_P_QINQ1
--#define ETH_P_QINQ1 0x9100 /* deprecated QinQ VLAN */
--#define ETH_P_QINQ2 0x9200 /* deprecated QinQ VLAN */
--#define ETH_P_QINQ3 0x9300 /* deprecated QinQ VLAN */
--#endif
--/* http://tools.ietf.org/html/rfc7133 */
--static inline __u16 parse_vlan_tags(const struct sk_buff *skb, struct ipt_netflow_tuple *tuple)
--{
-- /* no even untagged ethernet header */
-- if (skb_mac_header(skb) < skb->head ||
-- skb_mac_header(skb) + ETH_HLEN > skb->data)
-- return 0;
--
-- switch (eth_hdr(skb)->h_proto) {
-- case htons(ETH_P_QINQ1):
-- case htons(ETH_P_QINQ2):
-- case htons(ETH_P_QINQ3):
-- case htons(ETH_P_8021AD): /* S-TAG or B-TAG */
-- case htons(ETH_P_8021Q): /* C-TAG */
-- /* tagged and have full vlan header */
-- if (skb_mac_header(skb) + VLAN_ETH_HLEN <= skb->data)
-- break;
-- /* FALLTHROUGH */
-- default:
-- return eth_hdr(skb)->h_proto;
-- }
-
-- /* outer tag */
-- tuple->tag1 = vlan_eth_hdr(skb)->h_vlan_TCI;
-+static inline int eth_p_vlan(__be16 eth_type)
-+{
-+ return eth_type == htons(ETH_P_8021Q) ||
-+ eth_type == htons(ETH_P_8021AD);
-+}
-
-- switch (vlan_eth_hdr(skb)->h_vlan_encapsulated_proto) {
-- case htons(ETH_P_8021Q): /* C-TAG */
-- if (skb_mac_header(skb) + VLAN_ETH_H2LEN <= skb->data)
-- break;
-- /* FALLTHROUGH */
-- default:
-- return vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
-- }
-+/* Extract all L2 header data, currently (in iptables) skb->data is
-+ * pointing to network_header, so we use mac_header instead. */
-+/* Parse eth header, then vlans, then mpls. */
-+static void parse_l2_header(const struct sk_buff *skb, struct ipt_netflow_tuple *tuple)
-+{
-+#if defined(ENABLE_MAC) || defined(ENABLE_VLAN) || defined(MPLS_DEPTH)
-+#define ENABLE_L2
-+ unsigned char *mac_header = skb_mac_header(skb);
-+# if defined(ENABLE_VLAN) || defined(MPLS_DEPTH)
-+ unsigned int hdr_depth;
-+ __be16 proto;
-+# endif
-+# ifdef ENABLE_VLAN
-+ int tag_num = 0;
-
-- /* second tag */
-- tuple->tag2 = vlan_eth_hdr2(skb)->h2_vlan_TCI;
-- return vlan_eth_hdr2(skb)->h2_vlan_encapsulated_proto;
-+ /* get vlan tag that is saved in skb->vlan_tci */
-+ if (vlan_tx_tag_present(skb))
-+ tuple->tag[tag_num++] = htons(vlan_tx_tag_get(skb));
-+# endif
-+ if (mac_header < skb->head ||
-+ mac_header + ETH_HLEN > skb->data)
-+ return;
-+# ifdef ENABLE_MAC
-+ memcpy(&tuple->h_dst, eth_hdr(skb)->h_dest, ETH_ALEN);
-+ memcpy(&tuple->h_src, eth_hdr(skb)->h_source, ETH_ALEN);
-+# endif
-+# if defined(ENABLE_VLAN) || defined(MPLS_DEPTH)
-+ hdr_depth = ETH_HLEN;
-+ proto = eth_hdr(skb)->h_proto;
-+ if (eth_p_vlan(proto)) {
-+ do {
-+ const struct vlan_hdr *vh;
-+
-+ vh = (struct vlan_hdr *)(mac_header + hdr_depth);
-+ if (!skb_in_header(skb, vh, VLAN_HLEN))
-+ return;
-+ proto = vh->h_vlan_encapsulated_proto;
-+# ifdef ENABLE_VLAN
-+ if (tag_num < MAX_VLAN_TAGS)
-+ tuple->tag[tag_num++] = vh->h_vlan_TCI;
-+# endif
-+ hdr_depth += VLAN_HLEN;
-+ } while (eth_p_vlan(proto));
-+ }
-+# ifdef MPLS_DEPTH
-+ if (eth_p_mpls(proto)) {
-+ const struct mpls_label *mpls;
-+ int label_num = 0;
-+
-+ do {
-+ mpls = (struct mpls_label *)(mac_header + hdr_depth);
-+ if (!skb_in_header(skb, mpls, MPLS_HLEN))
-+ return;
-+ if (label_num < MPLS_DEPTH)
-+ tuple->mpls[label_num++] = mpls->entry;
-+ hdr_depth += MPLS_HLEN;
-+ } while (!(mpls->entry & htonl(MPLS_LS_S_MASK)));
-+ }
-+# endif
-+# endif /* defined(ENABLE_VLAN) || defined(MPLS_DEPTH) */
-+#endif /* defined(ENABLE_MAC) || defined(ENABLE_VLAN) || defined(MPLS_DEPTH) */
- }
--#endif /* ENABLE_VLAN */
-
- /* packet receiver */
- static unsigned int netflow_target(
-@@ -4622,6 +4748,8 @@ static unsigned int netflow_target(
- const void *targinfo
- # endif
- #else /* since 2.6.28 */
-+# define if_in par->in
-+# define if_out par->out
- # if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,35)
- const struct xt_target_param *par
- # else
-@@ -4631,7 +4759,11 @@ static unsigned int netflow_target(
- )
- {
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,24)
-- const struct sk_buff *skb = *pskb;
-+# ifndef ENABLE_L2
-+ /* pskb_may_pull() may modify skb */
-+ const
-+# endif
-+ struct sk_buff *skb = *pskb;
- #endif
- union {
- struct iphdr ip;
-@@ -4660,12 +4792,15 @@ static unsigned int netflow_target(
- int options = 0;
- int tcpoptions = 0;
- struct stripe_entry *stripe;
--#if defined(ENABLE_MAC) || defined(ENABLE_VLAN)
-- __be16 ethernetType = 0;
--#endif
-
-- iph = skb_header_pointer(skb, 0, (likely(family == AF_INET))? sizeof(_iph.ip) : sizeof(_iph.ip6), &iph);
-- if (unlikely(iph == NULL)) {
-+ if (unlikely(
-+#ifdef ENABLE_L2
-+ /* to ensure that full L2 headers are present */
-+ unlikely(!pskb_may_pull(skb, 0)) ||
-+#endif
-+ !(iph = skb_header_pointer(skb, 0,
-+ (likely(family == AF_INET))? sizeof(_iph.ip) : sizeof(_iph.ip6),
-+ &iph)))) {
- NETFLOW_STAT_INC(truncated);
- NETFLOW_STAT_INC(pkt_drop);
- NETFLOW_STAT_ADD(traf_drop, skb->len);
-@@ -4673,46 +4808,18 @@ static unsigned int netflow_target(
- return IPT_CONTINUE;
- }
-
--#ifdef ENABLE_DEBUGFS
-- if (atomic_read(&freeze)) {
-- NETFLOW_STAT_INC(freeze_err);
-- NETFLOW_STAT_INC(pkt_drop);
-- NETFLOW_STAT_ADD(traf_drop, skb->len);
-- NETFLOW_STAT_TS(drop);
-- return IPT_CONTINUE;
-- }
-+ memset(&tuple, 0, sizeof(tuple));
-+ tuple.l3proto = family;
-+#ifdef ENABLE_PHYSDEV_OVER
-+ if (skb->nf_bridge && skb->nf_bridge->physindev)
-+ tuple.i_ifc = skb->nf_bridge->physindev->ifindex;
-+ else /* FALLTHROUGH */
- #endif
--
-- tuple.l3proto = family;
-- tuple.s_port = 0;
-- tuple.d_port = 0;
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- tuple.i_ifc = if_in? if_in->ifindex : -1;
--#else
-- tuple.i_ifc = par->in? par->in->ifindex : -1;
--#endif
-- tcp_flags = 0; /* Cisco sometimes have TCP ACK for non TCP packets, don't get it */
-+ tcp_flags = 0;
- s_mask = 0;
- d_mask = 0;
--#ifdef ENABLE_MAC
-- if (skb_mac_header(skb) >= skb->head &&
-- skb_mac_header(skb) + ETH_HLEN <= skb->data) {
-- memcpy(&tuple.h_dst, eth_hdr(skb)->h_dest, ETH_ALEN);
-- memcpy(&tuple.h_src, eth_hdr(skb)->h_source, ETH_ALEN);
--#ifndef ENABLE_VLAN
-- ethernetType = eth_hdr(skb)->h_proto;
--#endif
-- } else {
-- memset(&tuple.h_dst, 0, ETH_ALEN);
-- memset(&tuple.h_src, 0, ETH_ALEN);
-- }
--#endif
--#ifdef ENABLE_VLAN
-- tuple.tag2 = tuple.tag1 = 0;
-- if (vlan_tx_tag_present(skb))
-- tuple.tag1 = htons(vlan_tx_tag_get(skb));
-- ethernetType = parse_vlan_tags(skb, &tuple);
--#endif
-+ parse_l2_header(skb, &tuple);
-
- if (likely(family == AF_INET)) {
- tuple.src = (union nf_inet_addr){ .ip = iph->ip.saddr };
-@@ -4832,16 +4939,16 @@ do_protocols:
- case IPPROTO_ICMP: {
- struct icmphdr _hdr, *hp;
-
-- if (likely(family == AF_INET &&
-- (hp = skb_header_pointer(skb, ptr, 2, &_hdr))))
-+ if (likely(family == AF_INET) &&
-+ likely(hp = skb_header_pointer(skb, ptr, 2, &_hdr)))
- tuple.d_port = htons((hp->type << 8) | hp->code);
- break;
- }
- case IPPROTO_ICMPV6: {
- struct icmp6hdr _icmp6h, *ic;
-
-- if (likely(family == AF_INET6 &&
-- (ic = skb_header_pointer(skb, ptr, 2, &_icmp6h))))
-+ if (likely(family == AF_INET6) &&
-+ likely(ic = skb_header_pointer(skb, ptr, 2, &_icmp6h)))
- tuple.d_port = htons((ic->icmp6_type << 8) | ic->icmp6_code);
- break;
- }
-@@ -4856,8 +4963,8 @@ do_protocols:
- struct ip_auth_hdr _hdr, *hp;
-
- /* This is for IPv4 only. IPv6 it's parsed above. */
-- if (likely(family == AF_INET &&
-- (hp = skb_header_pointer(skb, ptr, 8, &_hdr))))
-+ if (likely(family == AF_INET) &&
-+ likely(hp = skb_header_pointer(skb, ptr, 8, &_hdr)))
- SAVE_SPI(tuple, hp->spi);
- break;
- }
-@@ -4967,27 +5074,43 @@ do_protocols:
- #endif
- nf->nf_ts_first = jiffies;
- nf->tcp_flags = tcp_flags;
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
- nf->o_ifc = if_out? if_out->ifindex : -1;
--#else
-- nf->o_ifc = par->out? par->out->ifindex : -1;
-+#ifdef ENABLE_PHYSDEV_OVER
-+ if (skb->nf_bridge && skb->nf_bridge->physoutdev)
-+ nf->o_ifc = skb->nf_bridge->physoutdev->ifindex;
- #endif
-+
- #ifdef SNMP_RULES
- rcu_read_lock();
--# if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,28)
-+#else
-+# define resolve_snmp(dev) ((dev)? (dev)->ifindex : -1)
-+#endif
-+/* copy and snmp-resolve device with physdev overriding normal dev */
-+#define copy_dev(out, physdev, dev) \
-+ if (skb->nf_bridge && skb->nf_bridge->physdev) \
-+ out = resolve_snmp(skb->nf_bridge->physdev); \
-+ else \
-+ out = resolve_snmp(dev);
-+#ifdef ENABLE_PHYSDEV
-+ copy_dev(nf->o_ifphys, physoutdev, if_out);
-+ copy_dev(nf->i_ifphys, physindev, if_in);
-+#endif
-+#ifdef SNMP_RULES
-+# ifdef ENABLE_PHYSDEV_OVER
-+ copy_dev(nf->o_ifcr, physoutdev, if_out);
-+ copy_dev(nf->i_ifcr, physindev, if_in);
-+# else
- nf->o_ifcr = resolve_snmp(if_out);
- nf->i_ifcr = resolve_snmp(if_in);
--# else
-- nf->o_ifcr = resolve_snmp(par->out);
-- nf->i_ifcr = resolve_snmp(par->in);
- # endif
- rcu_read_unlock();
-+
- #endif
- nf->s_mask = s_mask;
- nf->d_mask = d_mask;
-
- #if defined(ENABLE_MAC) || defined(ENABLE_VLAN)
-- nf->ethernetType = ethernetType;
-+ nf->ethernetType = skb->protocol;
- #endif
-
- #if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,26)
-@@ -5034,7 +5157,7 @@ do_protocols:
-
- #define LIST_IS_NULL(name) (!(name)->next)
-
-- if (likely(active_needs_export(nf, active_timeout * HZ, jiffies))) {
-+ if (unlikely(active_needs_export(nf, active_timeout * HZ, jiffies))) {
- /* ok, if this is active flow to be exported */
- #ifdef HAVE_LLIST
- /* delete from hash and add to the export llist */
-@@ -5150,9 +5273,6 @@ static void register_ct_events(void)
- /* Reference netlink module to prevent it's unsafe unload before us. */
- if (!referenced && (netlink_m = find_module(NETLINK_M))) {
- referenced++;
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,35)
--#define use_module ref_module
--#endif
- use_module(THIS_MODULE, netlink_m);
- }
-
-@@ -5190,39 +5310,6 @@ static void unregister_ct_events(void)
- }
- #endif /* CONFIG_NF_NAT_NEEDED */
-
--#ifndef NF_IP_LOCAL_IN /* 2.6.25 */
--#define NF_IP_PRE_ROUTING NF_INET_PRE_ROUTING
--#define NF_IP_LOCAL_IN NF_INET_LOCAL_IN
--#define NF_IP_FORWARD NF_INET_FORWARD
--#define NF_IP_LOCAL_OUT NF_INET_LOCAL_OUT
--#define NF_IP_POST_ROUTING NF_INET_POST_ROUTING
--#endif
--
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,19)
--/* net/netfilter/x_tables.c */
--static void xt_unregister_targets(struct xt_target *target, unsigned int n)
--{
-- unsigned int i;
--
-- for (i = 0; i < n; i++)
-- xt_unregister_target(&target[i]);
--}
--static int xt_register_targets(struct xt_target *target, unsigned int n)
--{
-- unsigned int i;
--
-- int err = 0;
-- for (i = 0; i < n; i++)
-- if ((err = xt_register_target(&target[i])))
-- goto err;
-- return err;
--err:
-- if (i > 0)
-- xt_unregister_targets(target, i);
-- return err;
--}
--#endif
--
- static struct ipt_target ipt_netflow_reg[] __read_mostly = {
- {
- .name = "NETFLOW",
-@@ -5296,9 +5383,6 @@ static int __init ipt_netflow_init(void)
- clear_ipt_netflow_stat();
-
- if (!hashsize) {
--#if LINUX_VERSION_CODE >= KERNEL_VERSION(3,11,0)
--#define num_physpages totalram_pages
--#endif
- /* use 1/1024 of memory, 1M for hash table on 1G box */
- unsigned long memksize = (num_physpages << PAGE_SHIFT) / 1024;
-
-@@ -5318,6 +5402,11 @@ static int __init ipt_netflow_init(void)
- goto err;
- }
-
-+#ifdef MPLS_DEPTH
-+ if (MPLS_DEPTH >= 0 && MPLS_DEPTH < 10)
-+ template_mpls.types[MPLS_LABELS_BASE_INDEX + MPLS_DEPTH] = 0;
-+#endif
-+
- for (i = 0; i < LOCK_COUNT; i++) {
- spin_lock_init(&htable_stripes[i].lock);
- INIT_LIST_HEAD(&htable_stripes[i].list);
-@@ -5339,10 +5428,8 @@ static int __init ipt_netflow_init(void)
- goto err_free_netflow_slab;
- if (!register_stat("ipt_netflow_snmp", &snmp_seq_fops))
- goto err_free_proc_stat1;
--
--#ifdef ENABLE_DEBUGFS
-- flows_dump_d = debugfs_create_file("netflow_dump", S_IRUGO, NULL, NULL, &flows_dump_fops);
--#endif
-+ if (!register_stat("ipt_netflow_flows", &flows_seq_fops))
-+ goto err_free_proc_stat2;
-
- #ifdef CONFIG_SYSCTL
- ctl_table_renumber(netflow_sysctl_table);
-@@ -5357,7 +5444,7 @@ static int __init ipt_netflow_init(void)
- #endif
- if (!netflow_sysctl_header) {
- printk(KERN_ERR "netflow: can't register to sysctl\n");
-- goto err_free_proc_stat2;
-+ goto err_free_proc_stat3;
- } else
- printk(KERN_INFO "netflow: registered: sysctl net.netflow\n");
- #endif
-@@ -5443,12 +5530,11 @@ err_stop_timer:
- err_free_sysctl:
- #ifdef CONFIG_SYSCTL
- unregister_sysctl_table(netflow_sysctl_header);
--err_free_proc_stat2:
--#endif
--#ifdef ENABLE_DEBUGFS
-- debugfs_remove(flows_dump_d);
- #endif
-+err_free_proc_stat3:
- #ifdef CONFIG_PROC_FS
-+ remove_proc_entry("ipt_netflow_flows", INIT_NET(proc_net_stat));
-+err_free_proc_stat2:
- remove_proc_entry("ipt_netflow_snmp", INIT_NET(proc_net_stat));
- err_free_proc_stat1:
- remove_proc_entry("ipt_netflow", INIT_NET(proc_net_stat));
-@@ -5469,10 +5555,8 @@ static void __exit ipt_netflow_fini(void)
- #ifdef CONFIG_SYSCTL
- unregister_sysctl_table(netflow_sysctl_header);
- #endif
--#ifdef ENABLE_DEBUGFS
-- debugfs_remove(flows_dump_d);
--#endif
- #ifdef CONFIG_PROC_FS
-+ remove_proc_entry("ipt_netflow_flows", INIT_NET(proc_net_stat));
- remove_proc_entry("ipt_netflow_snmp", INIT_NET(proc_net_stat));
- remove_proc_entry("ipt_netflow", INIT_NET(proc_net_stat));
- #endif
-diff --git a/ipt_NETFLOW.h b/ipt_NETFLOW.h
-index 59512f0..eb00e94 100644
---- a/ipt_NETFLOW.h
-+++ b/ipt_NETFLOW.h
-@@ -16,8 +16,8 @@
- *
- */
-
--#ifndef _IP_NETFLOW_H
--#define _IP_NETFLOW_H
-+#ifndef _IPT_NETFLOW_H
-+#define _IPT_NETFLOW_H
-
- /*
- * Some tech info:
-@@ -113,9 +113,20 @@ struct netflow5_pdu {
- two(61, DIRECTION, flowDirection, 1) \
- two(62, IPV6_NEXT_HOP, ipNextHopIPv6Address, 16) \
- two(64, IPV6_OPTION_HEADERS, ipv6ExtensionHeaders, 2) \
-+ two(70, MPLS_LABEL_1, mplsTopLabelStackSection, 3) \
-+ two(71, MPLS_LABEL_2, mplsLabelStackSection2, 3) \
-+ two(72, MPLS_LABEL_3, mplsLabelStackSection3, 3) \
-+ two(73, MPLS_LABEL_4, mplsLabelStackSection4, 3) \
-+ two(74, MPLS_LABEL_5, mplsLabelStackSection5, 3) \
-+ two(75, MPLS_LABEL_6, mplsLabelStackSection6, 3) \
-+ two(76, MPLS_LABEL_7, mplsLabelStackSection7, 3) \
-+ two(77, MPLS_LABEL_8, mplsLabelStackSection8, 3) \
-+ two(78, MPLS_LABEL_9, mplsLabelStackSection9, 3) \
-+ two(79, MPLS_LABEL_10, mplsLabelStackSection10, 3) \
- one(80, destinationMacAddress, 6) \
- two(82, IF_NAME, interfaceName, IF_NAME_SZ) \
- two(83, IF_DESC, interfaceDescription, IF_DESC_SZ) \
-+ one(136, flowEndReason, 1) \
- one(138, observationPointId, 4) \
- one(139, icmpTypeCodeIPv6, 2) \
- one(141, LineCardId, 4) \
-@@ -135,6 +146,9 @@ struct netflow5_pdu {
- one(166, notSentFlowTotalCount, 8) \
- one(167, notSentPacketTotalCount, 8) \
- one(168, notSentOctetTotalCount, 8) \
-+ one(200, mplsTopLabelTTL, 1) \
-+ one(201, mplsLabelStackLength, 1) \
-+ one(202, mplsLabelStackDepth, 1) \
- one(208, ipv4Options, 4) \
- one(209, tcpOptions, 4) \
- one(225, postNATSourceIPv4Address, 4) \
-@@ -146,6 +160,8 @@ struct netflow5_pdu {
- one(244, dot1qPriority, 1) \
- one(245, dot1qCustomerVlanId, 2) \
- one(246, dot1qCustomerPriority, 1) \
-+ one(252, ingressPhysicalInterface, 2) \
-+ one(253, egressPhysicalInterface, 2) \
- one(256, ethernetType, 2) \
- one(295, IPSecSPI, 4) \
- one(300, observationDomainName, 128) \
-@@ -240,18 +256,10 @@ struct ipfix_pdu {
- * not searchable and will be exported soon. */
- #define FLOW_FULL_WATERMARK 0xffefffff
-
--#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,25)
--union nf_inet_addr {
-- __be32 ip;
-- __be32 ip6[4];
-- struct in_addr in;
-- struct in6_addr in6;
--};
--#endif
--
- #define EXTRACT_SPI(tuple) ((tuple.s_port << 16) | tuple.d_port)
- #define SAVE_SPI(tuple, spi) { tuple.s_port = spi >> 16; \
- tuple.d_port = spi; }
-+#define MAX_VLAN_TAGS 2
-
- /* hashed data which identify unique flow */
- /* 16+16 + 2+2 + 2+1+1+1 = 41 */
-@@ -260,10 +268,12 @@ struct ipt_netflow_tuple {
- union nf_inet_addr dst;
- __be16 s_port; // Network byte order
- __be16 d_port; // -"-
-+#ifdef MPLS_DEPTH
-+ __be32 mpls[MPLS_DEPTH]; /* Network byte order */
-+#endif
- __u16 i_ifc; // Host byte order
- #ifdef ENABLE_VLAN
-- __be16 tag1; // Network byte order (outer tag)
-- __be16 tag2; // -"-
-+ __be16 tag[MAX_VLAN_TAGS]; // Network byte order (outer tag first)
- #endif
- __u8 protocol;
- __u8 tos;
-@@ -287,13 +297,18 @@ struct ipt_netflow {
- __be16 ethernetType; /* Network byte order */
- #endif
- __u16 o_ifc;
-+#ifdef ENABLE_PHYSDEV
-+ __u16 i_ifphys;
-+ __u16 o_ifphys;
-+#endif
- #ifdef SNMP_RULES
-- __u16 i_ifcr;
-+ __u16 i_ifcr; /* translated interface numbers*/
- __u16 o_ifcr;
- #endif
- __u8 s_mask;
- __u8 d_mask;
- __u8 tcp_flags; /* `OR' of all tcp flags */
-+ __u8 flowEndReason;
- #ifdef ENABLE_DIRECTION
- __u8 hooknumx; /* hooknum + 1 */
- #endif
-@@ -362,8 +377,7 @@ static inline int ipt_netflow_tuple_equal(const struct ipt_netflow_tuple *t1,
- struct ipt_netflow_sock {
- struct list_head list;
- struct socket *sock;
-- __be32 ipaddr; // destination
-- unsigned short port;
-+ struct sockaddr_storage addr; // destination
- atomic_t wmem_peak; // sk_wmem_alloc peak value
- unsigned int err_connect; // connect errors
- unsigned int err_full; // socket filled error
-@@ -446,9 +460,6 @@ struct ipt_netflow_stat {
- unsigned int frags; // packets stat (drop)
- unsigned int maxflows_err; // maxflows reached (drop)
- unsigned int alloc_err; // failed to allocate memory (drop & lost)
--#ifdef ENABLE_DEBUGFS
-- unsigned int freeze_err; // freeze errors (drop)
--#endif
- struct duration drop;
- unsigned int send_success; // sendmsg() ok
- unsigned int send_failed; // sendmsg() failed
-@@ -478,10 +489,5 @@ struct ipt_netflow_stat {
- int metric; // one minute ewma of hash efficiency
- };
-
--#ifndef list_first_entry
--#define list_first_entry(ptr, type, member) \
-- list_entry((ptr)->next, type, member)
--#endif
--
- #endif
- /* vim: set sw=8: */
-diff --git a/snmp_NETFLOW.c b/snmp_NETFLOW.c
-index cf1d743..62457db 100644
---- a/snmp_NETFLOW.c
-+++ b/snmp_NETFLOW.c
-@@ -368,10 +368,10 @@ static int iptNetflowSysctl_handler(
- return sysctl_read(request, obj);
- case MODE_SET_RESERVE1:
- sys = find_varinfo(sysctls, obj);
-- if (request->requestvb->type != sys->type)
-- netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE);
-- if (!sysctl_access_ok(sys->name))
-+ if (!sys || !sysctl_access_ok(sys->name))
- netsnmp_request_set_error(request, SNMP_ERR_NOSUCHNAME);
-+ if (sys && request->requestvb->type != sys->type)
-+ netsnmp_request_set_error(request, SNMP_ERR_WRONGTYPE);
- break;
- case MODE_SET_RESERVE2:
- case MODE_SET_FREE:
-diff --git a/testing.sh b/testing.sh
-index b465c8d..45a0619 100755
---- a/testing.sh
-+++ b/testing.sh
-@@ -6,7 +6,7 @@ if [ "$1" = "" ]; then
- echo Maintainer only tool.
- exit 1
- elif [ "$1" = all ]; then
-- exec bash $0 linux-2.6.18 centos5 linux-3.11.2 centos6 linux-3.4.66 linux-3.9.11 centos7 linux-3.14 linux-3.17
-+ exec bash $0 linux-2.6.18 centos5 linux-3.11.2 centos6 linux-3.4.66 linux-3.9.11 centos7 linux-3.14 linux-3.17 linux-3.19
- exit 1
- fi
-
-@@ -28,11 +28,17 @@ readarray -t opts <<EOF
- --enable-snmp-rules
- --enable-macaddress
- --enable-vlan
-+ --promisc-mpls
- --enable-direction
- --enable-sampler
- --enable-sampler=hash
-- --enable-promisc
-+ --enable-promisc --promisc-mpls
-+ --enable-physdev
-+ --enable-physdev-override
- EOF
-+if [ "$SHORT" ]; then
-+ opts=("$SHORT")
-+fi
-
- colorecho() {
- echo -e "\033[1;32m$@\033[m"
-diff --git a/version.sh b/version.sh
-index e39433b..2509149 100755
---- a/version.sh
-+++ b/version.sh
-@@ -7,25 +7,29 @@ PATH=$PATH:/usr/local/bin:/usr/bin:/bin
- MVERSION=`sed -n 's/^#define.*IPT_NETFLOW_VERSION.*"\(.*\)".*/\1/p' ipt_NETFLOW.c`
-
- # GITVERSION overrides base version.
--if [ -e version.h ]; then
-+if [ -e version.h ] && grep -q GITVERSION version.h; then
- MVERSION=`sed -n 's/#define GITVERSION "\(.*\)".*/\1/p' version.h`
- fi
-
- # git describe overrides version from the source.
- if [ -d .git ] && which git >/dev/null 2>&1; then \
-- GVERSION=`git describe --dirty`
-- MVERSION=${GVERSION#v}
-+ GVERSION=`git describe --dirty 2>/dev/null`
-+ if [ "$GVERSION" ]; then
-+ MVERSION=${GVERSION#v}
-+ fi
- else
- GVERSION=
- fi
-
- if [ "$1" = --define ]; then
-- # output version.h which is GITVERSION or empty.
-+ # called from Makefile to create version.h
-+ # which should contain GITVERSION or be empty.
- if [ "$GVERSION" ]; then
- echo "#define GITVERSION \"$MVERSION\""
- else
-- echo "/* kernel doesn't like empty files */"
-+ echo "/* placeholder, because kernel doesn't like empty files */"
- fi
- else
-+ # normal run
- echo $MVERSION
- fi
diff --git a/testing/ipt-netflow-grsec/kernel-4.6.patch b/testing/ipt-netflow-grsec/kernel-4.6.patch
new file mode 100644
index 00000000000..79fba3c5bf0
--- /dev/null
+++ b/testing/ipt-netflow-grsec/kernel-4.6.patch
@@ -0,0 +1,63 @@
+From c16ffc6cb679b3377a0d4a30a6bbcf5e2f3d0214 Mon Sep 17 00:00:00 2001
+From: ABC <abc@telekom.ru>
+Date: Sun, 22 May 2016 22:07:14 +0300
+Subject: [PATCH] Support ETHTOOL_xLINKSETTINGS API (new in linux 4.6).
+
+Thus, making support for 4.6 kernels.
+Reference to linux commit:
+ https://github.com/torvalds/linux/commit/3f1ac7a700d
+
+Fixes #56, thanks karel-un.
+---
+ ipt_NETFLOW.c | 13 ++++++++++---
+ 1 file changed, 10 insertions(+), 3 deletions(-)
+
+diff --git a/ipt_NETFLOW.c b/ipt_NETFLOW.c
+index 067fd50..d27eea2 100644
+--- a/ipt_NETFLOW.c
++++ b/ipt_NETFLOW.c
+@@ -3904,7 +3904,13 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d
+ {
+ struct ethtool_drvinfo info = { 0 };
+ const struct ethtool_ops *ops = dev->ethtool_ops;
++#ifndef ETHTOOL_GLINKSETTINGS
+ struct ethtool_cmd ecmd;
++#define _KSETTINGS(x, y) (x)
++#else
++ struct ethtool_link_ksettings ekmd;
++#define _KSETTINGS(x, y) (y)
++#endif
+ int len = size;
+ int n;
+
+@@ -3933,11 +3939,11 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d
+ /* only get_settings for running devices to not trigger link negotiation */
+ if (dev->flags & IFF_UP &&
+ dev->flags & IFF_RUNNING &&
+- !__ethtool_get_settings(dev, &ecmd)) {
++ !_KSETTINGS(__ethtool_get_settings(dev, &ecmd), __ethtool_get_link_ksettings(dev, &ekmd))) {
+ char *s, *p;
+
+ /* append basic parameters: speed and port */
+- switch (ethtool_cmd_speed(&ecmd)) {
++ switch (_KSETTINGS(ethtool_cmd_speed(&ecmd), ekmd.base.speed)) {
+ case SPEED_10000: s = "10Gb"; break;
+ case SPEED_2500: s = "2.5Gb"; break;
+ case SPEED_1000: s = "1Gb"; break;
+@@ -3945,7 +3951,7 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d
+ case SPEED_10: s = "10Mb"; break;
+ default: s = "";
+ }
+- switch (ecmd.port) {
++ switch (_KSETTINGS(ecmd.port, ekmd.base.port)) {
+ case PORT_TP: p = "tp"; break;
+ case PORT_AUI: p = "aui"; break;
+ case PORT_MII: p = "mii"; break;
+@@ -3964,6 +3970,7 @@ static int ethtool_drvinfo(unsigned char *ptr, size_t size, struct net_device *d
+ ops->complete(dev);
+ return size - len;
+ }
++#undef _KSETTINGS
+
+ static const unsigned short netdev_type[] =
+ {ARPHRD_NETROM, ARPHRD_ETHER, ARPHRD_AX25,