diff --git a/target/linux/generic/pending-4.19/601-add-kernel-imq-support.patch b/target/linux/generic/pending-4.19/601-add-kernel-imq-support.patch index 3d5f1de1d2..734f0f7f31 100644 --- a/target/linux/generic/pending-4.19/601-add-kernel-imq-support.patch +++ b/target/linux/generic/pending-4.19/601-add-kernel-imq-support.patch @@ -1,6 +1,7 @@ ---- a/drivers/net/Kconfig 2018-04-22 23:17:57.583718674 -0400 -+++ b/drivers/net/Kconfig 2018-04-22 23:20:39.331768961 -0400 -@@ -277,6 +277,125 @@ +diff -Naupr linux-4.19.94_orig/drivers/net/Kconfig linux-4.19.94/drivers/net/Kconfig +--- linux-4.19.94_orig/drivers/net/Kconfig 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/drivers/net/Kconfig 2020-01-10 13:42:29.421018717 +0200 +@@ -278,6 +278,125 @@ config RIONET_RX_SIZE depends on RIONET default "128" @@ -126,9 +127,10 @@ config TUN tristate "Universal TUN/TAP device driver support" depends on INET ---- a/drivers/net/Makefile 2018-04-22 23:17:57.583718674 -0400 -+++ b/drivers/net/Makefile 2018-04-22 23:20:39.411768985 -0400 -@@ -13,6 +13,7 @@ +diff -Naupr linux-4.19.94_orig/drivers/net/Makefile linux-4.19.94/drivers/net/Makefile +--- linux-4.19.94_orig/drivers/net/Makefile 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/drivers/net/Makefile 2020-01-10 13:42:29.422018717 +0200 +@@ -13,6 +13,7 @@ obj-$(CONFIG_DUMMY) += dummy.o obj-$(CONFIG_EQUALIZER) += eql.o obj-$(CONFIG_IFB) += ifb.o obj-$(CONFIG_MACSEC) += macsec.o @@ -136,9 +138,10 @@ obj-$(CONFIG_MACVLAN) += macvlan.o obj-$(CONFIG_MACVTAP) += macvtap.o obj-$(CONFIG_MII) += mii.o ---- /dev/null 2018-03-30 15:39:24.291451107 -0400 -+++ b/drivers/net/imq.c 2018-05-20 11:10:23.471713282 -0400 -@@ -0,0 +1,1268 @@ +diff -Naupr linux-4.19.94_orig/drivers/net/imq.c linux-4.19.94/drivers/net/imq.c +--- linux-4.19.94_orig/drivers/net/imq.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.19.94/drivers/net/imq.c 2020-01-10 14:50:39.274108733 +0200 +@@ -0,0 +1,963 @@ +/* + * Pseudo-driver for the intermediate queue device. + * @@ -183,9 +186,9 @@ + +static nf_hookfn imq_nf_hook; + -+/*static struct nf_hook_ops imq_ops[] = { ++static struct nf_hook_ops imq_ops[] = { + { -+ // imq_ingress_ipv4 ++ /* imq_ingress_ipv4 */ + .hook = imq_nf_hook, + .pf = PF_INET, + .hooknum = NF_INET_PRE_ROUTING, @@ -196,7 +199,7 @@ +#endif + }, + { -+ // imq_egress_ipv4 ++ /* imq_egress_ipv4 */ + .hook = imq_nf_hook, + .pf = PF_INET, + .hooknum = NF_INET_POST_ROUTING, @@ -208,7 +211,7 @@ + }, +#if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) + { -+ // imq_ingress_ipv6 ++ /* imq_ingress_ipv6 */ + .hook = imq_nf_hook, + .pf = PF_INET6, + .hooknum = NF_INET_PRE_ROUTING, @@ -219,7 +222,7 @@ +#endif + }, + { -+ // imq_egress_ipv6 ++ /* imq_egress_ipv6 */ + .hook = imq_nf_hook, + .pf = PF_INET6, + .hooknum = NF_INET_POST_ROUTING, @@ -230,7 +233,7 @@ +#endif + }, +#endif -+};*/ ++}; + +#if defined(CONFIG_IMQ_NUM_DEVS) +static int numdevs = CONFIG_IMQ_NUM_DEVS; @@ -700,6 +703,7 @@ + int users; + int retval = -EINVAL; + unsigned int orig_queue_index; ++ bool again = false; + + dev->last_rx = jiffies; + @@ -739,7 +743,7 @@ + orig_queue_index = skb_get_queue_mapping(skb); + txq = imq_select_queue(dev, skb); + -+ q = rcu_dereference(txq->qdisc); ++ q = rcu_dereference_bh(txq->qdisc); + if (unlikely(!q->enqueue)) + goto packet_not_eaten_by_imq_dev; + @@ -776,7 +780,7 @@ + if (likely(skb_popd)) { + /* Note that we validate skb (GSO, checksum, ...) outside of locks */ + if (validate) -+ skb_popd = validate_xmit_skb_list(skb_popd, dev); ++ skb_popd = validate_xmit_skb_list(skb_popd, dev, &again); + + if (skb_popd) { + int dummy_ret; @@ -911,315 +915,16 @@ + .outfn = imq_nf_queue, +}; + -+static inline char *kernel_strdup(const char *str) -+{ -+ char *tmp; -+ long int s; -+ s=strlen(str) + 1; -+ tmp = kmalloc(s, GFP_ATOMIC); -+ if (tmp != NULL) -+ { -+ memcpy(tmp, str, s); -+ } -+ return tmp; -+} -+ -+/* -+ * line is the line to be parsed -- it is not modified in any way -+ * max_pieces indicates number of pieces to return, if negative this is determined dynamically -+ * include_remainder_at_max indicates whether the last piece, when max pieces are reached, -+ * should be what it would normally be (0) or the entire remainder of the line (1) -+ * if max_pieces < 0 this parameter is ignored -+ * -+ * -+ * returns all non-separator pieces in a line -+ * result is dynamically allocated, MUST be freed after call-- even if -+ * line is empty (you still get a valid char** pointer to to a NULL char*) -+ */ -+char** split_on_separators(char* line, char* separators, int num_separators, int max_pieces, int include_remainder_at_max, unsigned long *num_pieces) -+{ -+ char** split; -+ -+ *num_pieces = 0; -+ if(line != NULL) -+ { -+ int split_index; -+ int non_separator_found; -+ char* dup_line; -+ char* start; -+ -+ if(max_pieces < 0) -+ { -+ /* count number of separator characters in line -- this count + 1 is an upperbound on number of pieces */ -+ int separator_count = 0; -+ int line_index; -+ for(line_index = 0; line[line_index] != '\0'; line_index++) -+ { -+ int sep_index; -+ int found = 0; -+ for(sep_index =0; found == 0 && sep_index < num_separators; sep_index++) -+ { -+ found = separators[sep_index] == line[line_index] ? 1 : 0; -+ } -+ separator_count = separator_count+ found; -+ } -+ max_pieces = separator_count + 1; -+ } -+ split = (char**)kmalloc((1+max_pieces)*sizeof(char*), GFP_ATOMIC); -+ split_index = 0; -+ split[split_index] = NULL; -+ -+ -+ dup_line = kernel_strdup(line); -+ start = dup_line; -+ non_separator_found = 0; -+ while(non_separator_found == 0) -+ { -+ int matches = 0; -+ int sep_index; -+ for(sep_index =0; sep_index < num_separators; sep_index++) -+ { -+ matches = matches == 1 || separators[sep_index] == start[0] ? 1 : 0; -+ } -+ non_separator_found = matches==0 || start[0] == '\0' ? 1 : 0; -+ if(non_separator_found == 0) -+ { -+ start++; -+ } -+ } -+ -+ while(start[0] != '\0' && split_index < max_pieces) -+ { -+ /* find first separator index */ -+ int first_separator_index = 0; -+ int separator_found = 0; -+ while( separator_found == 0 ) -+ { -+ int sep_index; -+ for(sep_index =0; separator_found == 0 && sep_index < num_separators; sep_index++) -+ { -+ separator_found = separators[sep_index] == start[first_separator_index] || start[first_separator_index] == '\0' ? 1 : 0; -+ } -+ if(separator_found == 0) -+ { -+ first_separator_index++; -+ } -+ } -+ -+ /* copy next piece to split array */ -+ if(first_separator_index > 0) -+ { -+ char* next_piece = NULL; -+ if(split_index +1 < max_pieces || include_remainder_at_max <= 0) -+ { -+ next_piece = (char*)kmalloc((first_separator_index+1)*sizeof(char), GFP_ATOMIC); -+ memcpy(next_piece, start, first_separator_index); -+ next_piece[first_separator_index] = '\0'; -+ } -+ else -+ { -+ next_piece = kernel_strdup(start); -+ } -+ split[split_index] = next_piece; -+ split[split_index+1] = NULL; -+ split_index++; -+ } -+ -+ -+ /* find next non-separator index, indicating start of next piece */ -+ start = start+ first_separator_index; -+ non_separator_found = 0; -+ while(non_separator_found == 0) -+ { -+ int matches = 0; -+ int sep_index; -+ for(sep_index =0; sep_index < num_separators; sep_index++) -+ { -+ matches = matches == 1 || separators[sep_index] == start[0] ? 1 : 0; -+ } -+ non_separator_found = matches==0 || start[0] == '\0' ? 1 : 0; -+ if(non_separator_found == 0) -+ { -+ start++; -+ } -+ } -+ } -+ kfree(dup_line); -+ *num_pieces = split_index; -+ } -+ else -+ { -+ split = (char**)kmalloc((1)*sizeof(char*), GFP_ATOMIC); -+ split[0] = NULL; -+ } -+ return split; -+} -+ -+ -+/* returns number freed */ -+int free_null_terminated_string_array(char** strs) -+{ -+ unsigned long str_index = 0; -+ if(strs != NULL) -+ { -+ for(str_index=0; strs[str_index] != NULL; str_index++) -+ { -+ kfree(strs[str_index]); -+ } -+ kfree(strs); -+ } -+ return str_index; -+} -+ -+ -+ -+#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB) -+ #define DEFAULT_PRE_TABLE "mangle" -+#else -+ #define DEFAULT_PRE_TABLE "nat" -+#endif -+ -+#if defined(CONFIG_IMQ_BEHAVIOR_AA) || defined(CONFIG_IMQ_BEHAVIOR_BA) -+ #define DEFAULT_POST_TABLE "nat" -+#else -+ #define DEFAULT_POST_TABLE "mangle" -+#endif -+ -+static char* hook_chains = "PREROUTING,POSTROUTING"; -+static char* hook_tables = DEFAULT_PRE_TABLE","DEFAULT_POST_TABLE; -+ -+static struct nf_hook_ops* hook_list = NULL; -+static int hook_list_length = 0; -+ +static int __net_init imq_nf_register(struct net *net) +{ -+ int ret; -+ char separators[4] = {',', ' ', '\t', '\0' }; -+ unsigned long num_chains; -+ unsigned long num_tables; -+ char** chain_list = split_on_separators(hook_chains, separators, 3, -1, 0, &num_chains); -+ char** table_list = split_on_separators(hook_tables, separators, 3, -1, 0, &num_tables); -+ int hook_index = 0; -+ -+ hook_list_length = 0; -+ if(num_chains != num_tables) -+ { -+ printk("ERROR: must have same number of chains and tables\n"); -+ return -1; -+ } -+ -+ /* we multiply by 2 here since we need hooks for both IPv4 and IPv6 */ -+ hook_list = (struct nf_hook_ops*)kmalloc(sizeof(struct nf_hook_ops)*((num_chains*2)+1), GFP_ATOMIC); -+ -+ -+ for(hook_index=0; hook_index < num_chains; hook_index++) -+ { -+ char* chain = chain_list[hook_index]; -+ char* table = table_list[hook_index]; -+ int valid = 0; -+ if(strcmp(chain, "PREROUTING") == 0 || strcmp(chain, "POSTROUTING") == 0 || strcmp(chain, "INPUT") == 0 || strcmp(chain, "FORWARD") == 0 || strcmp(chain, "OUTPUT") == 0) -+ { -+ if( strcmp(table, "mangle") == 0 || -+ (strcmp(table, "nat") == 0 && strcmp(chain, "FORWARD") != 0 && strcmp(chain, "INPUT") != 0 ) || -+ (strcmp(table, "filter") == 0 && strcmp(chain, "PREROUTING") != 0 && strcmp(chain, "POSTROUTING") != 0 ) -+ ) -+ { -+ unsigned int chain_id = NF_INET_PRE_ROUTING; -+ int table_id = NF_IP_PRI_MANGLE; -+ int err = 0; -+ -+ valid = 1; -+ -+ if(strcmp(chain, "PREROUTING") == 0) -+ { -+ chain_id = NF_INET_PRE_ROUTING; -+ } -+ else if (strcmp(chain, "POSTROUTING") == 0) -+ { -+ chain_id = NF_INET_POST_ROUTING; -+ } -+ else if (strcmp(chain, "INPUT") == 0) -+ { -+ chain_id = NF_INET_LOCAL_IN; -+ -+ } -+ else if (strcmp(chain, "FORWARD") == 0) -+ { -+ chain_id = NF_INET_FORWARD; -+ -+ } -+ else if (strcmp(chain, "OUTPUT") == 0) -+ { -+ chain_id = NF_INET_LOCAL_OUT; -+ } -+ -+ if(strcmp(table, "mangle") == 0) -+ { -+ table_id = NF_IP_PRI_MANGLE+1; -+ } -+ else if (strcmp(table, "nat") == 0 && strcmp(chain, "POSTROUTING") == 0) -+ { -+ table_id = NF_IP_PRI_NAT_SRC+1; -+ } -+ else if (strcmp(table, "nat") == 0 && strcmp(chain, "POSTROUTING") != 0) -+ { -+ table_id = NF_IP_PRI_NAT_DST+1; -+ } -+ else if (strcmp(table, "filter") == 0) -+ { -+ table_id = NF_IP_PRI_FILTER+1; -+ } -+ (hook_list[hook_list_length]).hook = imq_nf_hook; -+ (hook_list[hook_list_length]).pf = PF_INET; -+ (hook_list[hook_list_length]).hooknum = chain_id; -+ (hook_list[hook_list_length]).priority = table_id; -+ printk(KERN_INFO "\tIMQv4: Hooking IMQ after %s on %s, pf=%d, hooknum=%d, priority=%d\n", table, chain, (hook_list[hook_list_length]).pf, (hook_list[hook_list_length]).hooknum, (hook_list[hook_list_length]).priority); -+ hook_list_length++; -+ -+ #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) -+ if(strcmp(table, "mangle") == 0) -+ { -+ table_id = NF_IP6_PRI_MANGLE+1; -+ } -+ else if (strcmp(table, "nat") == 0 && strcmp(chain, "POSTROUTING") == 0) -+ { -+ table_id = NF_IP6_PRI_NAT_SRC+1; -+ } -+ else if (strcmp(table, "nat") == 0 && strcmp(chain, "POSTROUTING") != 0) -+ { -+ table_id = NF_IP6_PRI_NAT_DST+1; -+ } -+ else if (strcmp(table, "filter") == 0) -+ { -+ table_id = NF_IP6_PRI_FILTER+1; -+ } -+ -+ (hook_list[hook_list_length]).hook = imq_nf_hook; -+ (hook_list[hook_list_length]).pf = PF_INET6; -+ (hook_list[hook_list_length]).hooknum = chain_id; -+ (hook_list[hook_list_length]).priority = table_id; -+ printk(KERN_INFO "\tIMQv6: Hooking IMQ after %s on %s, pf=%d, hooknum=%d, priority=%d\n", table, chain, (hook_list[hook_list_length]).pf, (hook_list[hook_list_length]).hooknum, (hook_list[hook_list_length]).priority); -+ hook_list_length++; -+ #endif -+ } -+ } -+ if(valid == 0) -+ { -+ printk("ERROR: invalid chain/table at index %d (%s/%s)\n", hook_index, chain, table); -+ } -+ } -+ free_null_terminated_string_array(chain_list); -+ free_null_terminated_string_array(table_list); -+ -+ return nf_register_net_hooks(net, hook_list, -+ hook_list_length); ++ return nf_register_net_hooks(net, imq_ops, ++ ARRAY_SIZE(imq_ops)); +}; + -+ +static void __net_exit imq_nf_unregister(struct net *net) +{ -+ nf_unregister_net_hooks(net, hook_list, -+ hook_list_length); ++ nf_unregister_net_hooks(net, imq_ops, ++ ARRAY_SIZE(imq_ops)); +}; + +static struct pernet_operations imq_net_ops = { @@ -1229,7 +934,7 @@ + +static int __net_init imq_init_hooks(void) +{ -+ int ret ; ++ int ret; + nf_register_queue_imq_handler(&imq_nfqh); + + ret = register_pernet_subsys(&imq_net_ops); @@ -1352,7 +1057,7 @@ + + pr_info("IMQ driver loaded successfully. (numdevs = %d, numqueues = %d, imq_dev_accurate_stats = %d)\n", + numdevs, numqueues, imq_dev_accurate_stats); -+/* ++ +#if defined(CONFIG_IMQ_BEHAVIOR_BA) || defined(CONFIG_IMQ_BEHAVIOR_BB) + pr_info("\tHooking IMQ before NAT on PREROUTING.\n"); +#else @@ -1363,7 +1068,7 @@ +#else + pr_info("\tHooking IMQ after NAT on POSTROUTING.\n"); +#endif -+*/ ++ + return 0; +} + @@ -1371,9 +1076,6 @@ +{ + unregister_pernet_subsys(&imq_net_ops); + nf_unregister_queue_imq_handler(); -+ -+ kfree(hook_list); -+ hook_list_length = 0; +} + +static void __exit imq_cleanup_devs(void) @@ -1395,20 +1097,17 @@ +module_param(numdevs, int, 0); +module_param(numqueues, int, 0); +module_param(imq_dev_accurate_stats, int, 0); -+module_param(hook_chains, charp, 0); -+module_param(hook_tables, charp, 0); +MODULE_PARM_DESC(numdevs, "number of IMQ devices (how many imq* devices will be created)"); +MODULE_PARM_DESC(numqueues, "number of queues per IMQ device"); +MODULE_PARM_DESC(imq_dev_accurate_stats, "Notify if need the accurate imq device stats"); -+MODULE_PARM_DESC(hook_chains, "netfilter chains in which to insert hooks to IMQ"); -+MODULE_PARM_DESC(hook_tables, "netfilter tables after which to insert hooks to IMQ"); + +MODULE_AUTHOR("https://github.com/imq/linuximq"); +MODULE_DESCRIPTION("Pseudo-driver for the intermediate queue device. See https://github.com/imq/linuximq/wiki for more information."); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_RTNL_LINK("imq"); ---- /dev/null 2018-03-30 15:39:24.291451107 -0400 -+++ b/include/linux/imq.h 2018-04-22 23:20:39.411768985 -0400 +diff -Naupr linux-4.19.94_orig/include/linux/imq.h linux-4.19.94/include/linux/imq.h +--- linux-4.19.94_orig/include/linux/imq.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.19.94/include/linux/imq.h 2020-01-10 13:42:30.105018732 +0200 @@ -0,0 +1,13 @@ +#ifndef _IMQ_H +#define _IMQ_H @@ -1423,9 +1122,10 @@ + +#endif /* _IMQ_H */ + ---- a/include/linux/netdevice.h 2018-04-22 23:18:14.351723881 -0400 -+++ b/include/linux/netdevice.h 2018-04-22 23:20:39.411768985 -0400 -@@ -1785,6 +1785,11 @@ +diff -Naupr linux-4.19.94_orig/include/linux/netdevice.h linux-4.19.94/include/linux/netdevice.h +--- linux-4.19.94_orig/include/linux/netdevice.h 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/include/linux/netdevice.h 2020-01-10 13:42:30.106018732 +0200 +@@ -1905,6 +1905,11 @@ struct net_device { /* * Cache lines mostly used on receive path (including eth_type_trans()) */ @@ -1437,7 +1137,7 @@ /* Interface address info used in eth_type_trans() */ unsigned char *dev_addr; -@@ -3646,6 +3651,19 @@ +@@ -3938,6 +3943,19 @@ static inline void netif_tx_unlock_bh(st } \ } @@ -1457,8 +1157,9 @@ static inline void netif_tx_disable(struct net_device *dev) { unsigned int i; ---- /dev/null 2018-03-30 15:39:24.291451107 -0400 -+++ b/include/linux/netfilter/xt_IMQ.h 2018-04-22 23:20:39.415768987 -0400 +diff -Naupr linux-4.19.94_orig/include/linux/netfilter/xt_IMQ.h linux-4.19.94/include/linux/netfilter/xt_IMQ.h +--- linux-4.19.94_orig/include/linux/netfilter/xt_IMQ.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.19.94/include/linux/netfilter/xt_IMQ.h 2020-01-10 13:42:30.107018732 +0200 @@ -0,0 +1,9 @@ +#ifndef _XT_IMQ_H +#define _XT_IMQ_H @@ -1469,8 +1170,9 @@ + +#endif /* _XT_IMQ_H */ + ---- /dev/null 2018-03-30 15:39:24.291451107 -0400 -+++ b/include/linux/netfilter_ipv4/ipt_IMQ.h 2018-04-22 23:20:39.415768987 -0400 +diff -Naupr linux-4.19.94_orig/include/linux/netfilter_ipv4/ipt_IMQ.h linux-4.19.94/include/linux/netfilter_ipv4/ipt_IMQ.h +--- linux-4.19.94_orig/include/linux/netfilter_ipv4/ipt_IMQ.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.19.94/include/linux/netfilter_ipv4/ipt_IMQ.h 2020-01-10 13:42:30.107018732 +0200 @@ -0,0 +1,10 @@ +#ifndef _IPT_IMQ_H +#define _IPT_IMQ_H @@ -1482,8 +1184,9 @@ + +#endif /* _IPT_IMQ_H */ + ---- /dev/null 2018-03-30 15:39:24.291451107 -0400 -+++ b/include/linux/netfilter_ipv6/ip6t_IMQ.h 2018-04-22 23:20:39.415768987 -0400 +diff -Naupr linux-4.19.94_orig/include/linux/netfilter_ipv6/ip6t_IMQ.h linux-4.19.94/include/linux/netfilter_ipv6/ip6t_IMQ.h +--- linux-4.19.94_orig/include/linux/netfilter_ipv6/ip6t_IMQ.h 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.19.94/include/linux/netfilter_ipv6/ip6t_IMQ.h 2020-01-10 13:42:30.107018732 +0200 @@ -0,0 +1,10 @@ +#ifndef _IP6T_IMQ_H +#define _IP6T_IMQ_H @@ -1495,8 +1198,9 @@ + +#endif /* _IP6T_IMQ_H */ + ---- a/include/linux/skbuff.h 2018-04-22 23:18:15.079724108 -0400 -+++ b/include/linux/skbuff.h 2018-04-22 23:20:39.415768987 -0400 +diff -Naupr linux-4.19.94_orig/include/linux/skbuff.h linux-4.19.94/include/linux/skbuff.h +--- linux-4.19.94_orig/include/linux/skbuff.h 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/include/linux/skbuff.h 2020-01-10 14:06:24.162050295 +0200 @@ -40,6 +40,10 @@ #include #include @@ -1508,7 +1212,7 @@ /* The interface for checksum offload between the stack and networking drivers * is as follows... -@@ -582,7 +586,7 @@ +@@ -587,7 +591,7 @@ typedef unsigned int sk_buff_data_t; typedef unsigned char *sk_buff_data_t; #endif @@ -1517,7 +1221,7 @@ * struct sk_buff - socket buffer * @next: Next buffer in list * @prev: Previous buffer in list -@@ -685,6 +689,9 @@ +@@ -698,6 +702,9 @@ struct sk_buff { * first. This is owned by whoever has the skb queued ATM. */ char cb[48] __aligned(8); @@ -1525,9 +1229,9 @@ + void *cb_next; +#endif - unsigned long _skb_refdst; - void (*destructor)(struct sk_buff *skb); -@@ -694,6 +701,9 @@ + union { + struct { +@@ -713,6 +720,9 @@ struct sk_buff { #if defined(CONFIG_NF_CONNTRACK) || defined(CONFIG_NF_CONNTRACK_MODULE) unsigned long _nfct; #endif @@ -1537,9 +1241,9 @@ #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) struct nf_bridge_info *nf_bridge; #endif -@@ -771,6 +781,9 @@ - #ifdef CONFIG_NET_SWITCHDEV +@@ -790,6 +800,9 @@ struct sk_buff { __u8 offload_fwd_mark:1; + __u8 offload_mr_fwd_mark:1; #endif +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) + __u8 imq_flags:IMQ_F_BITS; @@ -1547,7 +1251,7 @@ #ifdef CONFIG_NET_CLS_ACT __u8 tc_skip_classify:1; __u8 tc_at_ingress:1; -@@ -870,7 +883,7 @@ +@@ -889,7 +902,7 @@ static inline bool skb_pfmemalloc(const */ static inline struct dst_entry *skb_dst(const struct sk_buff *skb) { @@ -1556,7 +1260,7 @@ * rcu_read_lock section */ WARN_ON((skb->_skb_refdst & SKB_DST_NOREF) && -@@ -960,6 +973,12 @@ +@@ -979,6 +992,12 @@ void skb_tx_error(struct sk_buff *skb); void consume_skb(struct sk_buff *skb); void __consume_stateless_skb(struct sk_buff *skb); void __kfree_skb(struct sk_buff *skb); @@ -1569,13 +1273,13 @@ extern struct kmem_cache *skbuff_head_cache; void kfree_skb_partial(struct sk_buff *skb, bool head_stolen); -@@ -3779,8 +3798,12 @@ +@@ -3922,8 +3941,12 @@ static inline void __nf_copy(struct sk_b dst->_nfct = src->_nfct; nf_conntrack_get(skb_nfct(src)); #endif +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) + dst->imq_flags = src->imq_flags; -+ dst->nf_queue_entry = src->nf_queue_entry; ++ dst->nf_queue_entry = src->nf_queue_entry; +#endif #if IS_ENABLED(CONFIG_BRIDGE_NETFILTER) - dst->nf_bridge = src->nf_bridge; @@ -1583,9 +1287,10 @@ nf_bridge_get(src->nf_bridge); #endif #if IS_ENABLED(CONFIG_NETFILTER_XT_TARGET_TRACE) || defined(CONFIG_NF_TABLES) ---- a/include/net/netfilter/nf_queue.h 2018-04-22 23:18:15.199724146 -0400 -+++ b/include/net/netfilter/nf_queue.h 2018-04-22 23:20:39.419768987 -0400 -@@ -31,6 +31,12 @@ +diff -Naupr linux-4.19.94_orig/include/net/netfilter/nf_queue.h linux-4.19.94/include/net/netfilter/nf_queue.h +--- linux-4.19.94_orig/include/net/netfilter/nf_queue.h 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/include/net/netfilter/nf_queue.h 2020-01-10 13:42:30.109018732 +0200 +@@ -31,6 +31,12 @@ struct nf_queue_handler { void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh); void nf_unregister_queue_handler(struct net *net); void nf_reinject(struct nf_queue_entry *entry, unsigned int verdict); @@ -1598,9 +1303,10 @@ void nf_queue_entry_get_refs(struct nf_queue_entry *entry); void nf_queue_entry_release_refs(struct nf_queue_entry *entry); ---- a/include/net/pkt_sched.h 2018-04-22 23:18:15.219724151 -0400 -+++ b/include/net/pkt_sched.h 2018-04-22 23:20:39.419768987 -0400 -@@ -109,6 +109,8 @@ +diff -Naupr linux-4.19.94_orig/include/net/pkt_sched.h linux-4.19.94/include/net/pkt_sched.h +--- linux-4.19.94_orig/include/net/pkt_sched.h 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/include/net/pkt_sched.h 2020-01-10 13:42:30.109018732 +0200 +@@ -114,6 +114,8 @@ bool sch_direct_xmit(struct sk_buff *skb void __qdisc_run(struct Qdisc *q); @@ -1608,10 +1314,11 @@ + static inline void qdisc_run(struct Qdisc *q) { - if (qdisc_run_begin(q)) ---- a/include/net/sch_generic.h 2018-04-22 23:18:15.227724154 -0400 -+++ b/include/net/sch_generic.h 2018-04-22 23:20:39.419768987 -0400 -@@ -567,6 +567,13 @@ + if (qdisc_run_begin(q)) { +diff -Naupr linux-4.19.94_orig/include/net/sch_generic.h linux-4.19.94/include/net/sch_generic.h +--- linux-4.19.94_orig/include/net/sch_generic.h 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/include/net/sch_generic.h 2020-01-10 13:42:30.109018732 +0200 +@@ -704,6 +704,13 @@ static inline int qdisc_enqueue(struct s return sch->enqueue(skb, sch, to_free); } @@ -1625,8 +1332,9 @@ static inline bool qdisc_is_percpu_stats(const struct Qdisc *q) { return q->flags & TCQ_F_CPUSTATS; ---- a/include/uapi/linux/netfilter.h 2018-04-22 23:18:16.159724442 -0400 -+++ b/include/uapi/linux/netfilter.h 2018-04-22 23:20:39.419768987 -0400 +diff -Naupr linux-4.19.94_orig/include/uapi/linux/netfilter.h linux-4.19.94/include/uapi/linux/netfilter.h +--- linux-4.19.94_orig/include/uapi/linux/netfilter.h 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/include/uapi/linux/netfilter.h 2020-01-10 13:42:30.109018732 +0200 @@ -14,7 +14,8 @@ #define NF_QUEUE 3 #define NF_REPEAT 4 @@ -1637,9 +1345,10 @@ /* we overload the higher bits for encoding auxiliary data such as the queue * number or errno values. Not nice, but better than additional function ---- a/net/core/dev.c 2018-04-22 23:18:24.391727000 -0400 -+++ b/net/core/dev.c 2018-04-22 23:20:39.419768987 -0400 -@@ -143,6 +143,9 @@ +diff -Naupr linux-4.19.94_orig/net/core/dev.c linux-4.19.94/net/core/dev.c +--- linux-4.19.94_orig/net/core/dev.c 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/net/core/dev.c 2020-01-10 13:42:30.110018732 +0200 +@@ -142,6 +142,9 @@ #include #include #include @@ -1648,8 +1357,8 @@ +#endif #include #include - -@@ -2979,7 +2982,12 @@ + #include +@@ -3250,7 +3253,12 @@ static int xmit_one(struct sk_buff *skb, unsigned int len; int rc; @@ -1661,8 +1370,8 @@ +#endif dev_queue_xmit_nit(skb, dev); - #ifdef CONFIG_ETHERNET_PACKET_MANGLE -@@ -3028,6 +3036,8 @@ + len = skb->len; +@@ -3289,6 +3297,8 @@ out: return skb; } @@ -1671,10 +1380,11 @@ static struct sk_buff *validate_xmit_vlan(struct sk_buff *skb, netdev_features_t features) { ---- a/net/core/skbuff.c 2018-04-22 23:18:24.395727003 -0400 -+++ b/net/core/skbuff.c 2018-04-22 23:20:39.419768987 -0400 -@@ -82,6 +82,87 @@ - static struct kmem_cache *skbuff_fclone_cache __read_mostly; +diff -Naupr linux-4.19.94_orig/net/core/skbuff.c linux-4.19.94/net/core/skbuff.c +--- linux-4.19.94_orig/net/core/skbuff.c 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/net/core/skbuff.c 2020-01-10 13:53:44.039033565 +0200 +@@ -81,6 +81,58 @@ struct kmem_cache *skbuff_head_cache __r + static struct kmem_cache *skbuff_fclone_cache __ro_after_init; int sysctl_max_skb_frags __read_mostly = MAX_SKB_FRAGS; EXPORT_SYMBOL(sysctl_max_skb_frags); +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) @@ -1689,8 +1399,6 @@ + atomic_t refcnt; +}; + -+static DEFINE_SPINLOCK(skb_cb_store_lock); -+ +int skb_save_cb(struct sk_buff *skb) +{ + struct skb_cb_table *next; @@ -1703,10 +1411,9 @@ + + memcpy(next->cb, skb->cb, sizeof(skb->cb)); + next->cb_next = skb->cb_next; -+ -+ atomic_set(&next->refcnt, 1); -+ + skb->cb_next = next; ++ smp_wmb(); ++ + return 0; +} +EXPORT_SYMBOL(skb_save_cb); @@ -1724,44 +1431,18 @@ + + memcpy(skb->cb, next->cb, sizeof(skb->cb)); + skb->cb_next = next->cb_next; ++ smp_wmb(); + -+ spin_lock(&skb_cb_store_lock); -+ -+ if (atomic_dec_and_test(&next->refcnt)) -+ kmem_cache_free(skbuff_cb_store_cache, next); -+ -+ spin_unlock(&skb_cb_store_lock); ++ kmem_cache_free(skbuff_cb_store_cache, next); + + return 0; +} +EXPORT_SYMBOL(skb_restore_cb); -+ -+static void skb_copy_stored_cb(struct sk_buff * , const struct sk_buff * ) __attribute__ ((unused)); -+static void skb_copy_stored_cb(struct sk_buff *new, const struct sk_buff *__old) -+{ -+ struct skb_cb_table *next; -+ struct sk_buff *old; -+ -+ if (!__old->cb_next) { -+ new->cb_next = NULL; -+ return; -+ } -+ -+ spin_lock(&skb_cb_store_lock); -+ -+ old = (struct sk_buff *)__old; -+ -+ next = old->cb_next; -+ atomic_inc(&next->refcnt); -+ new->cb_next = next; -+ -+ spin_unlock(&skb_cb_store_lock); -+} +#endif /** * skb_panic - private function for out-of-line support -@@ -628,6 +709,28 @@ +@@ -615,6 +667,28 @@ void skb_release_head_state(struct sk_bu WARN_ON(in_irq()); skb->destructor(skb); } @@ -1790,18 +1471,17 @@ #if IS_ENABLED(CONFIG_NF_CONNTRACK) nf_conntrack_put(skb_nfct(skb)); #endif -@@ -817,6 +920,10 @@ +@@ -804,6 +878,9 @@ static void __copy_skb_header(struct sk_ new->sp = secpath_get(old->sp); #endif __nf_copy(new, old, false); +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) + new->cb_next = NULL; -+ /*skb_copy_stored_cb(new, old);*/ +#endif /* Note : this field could be in headers_start/headers_end section * It is not yet because we do not want to have a 16 bit hole -@@ -3915,6 +4022,13 @@ +@@ -3969,6 +4046,13 @@ void __init skb_init(void) 0, SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); @@ -1815,23 +1495,10 @@ } static int ---- a/net/netfilter/core.c 2018-04-22 23:18:26.019727507 -0400 -+++ b/net/netfilter/core.c 2018-04-22 23:20:39.419768987 -0400 -@@ -457,6 +457,11 @@ - if (ret == 0) - ret = -EPERM; - return ret; -+ case NF_IMQ_QUEUE: -+ ret = nf_queue(skb, state, e, s, verdict); -+ if (ret == -ECANCELED) -+ continue; -+ return ret; - case NF_QUEUE: - ret = nf_queue(skb, state, e, s, verdict); - if (ret == 1) ---- a/net/netfilter/Kconfig 2018-04-22 23:18:25.751727424 -0400 -+++ b/net/netfilter/Kconfig 2018-04-22 23:20:39.419768987 -0400 -@@ -902,6 +902,18 @@ +diff -Naupr linux-4.19.94_orig/net/netfilter/Kconfig linux-4.19.94/net/netfilter/Kconfig +--- linux-4.19.94_orig/net/netfilter/Kconfig 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/net/netfilter/Kconfig 2020-01-10 13:42:30.111018732 +0200 +@@ -920,6 +920,18 @@ config NETFILTER_XT_TARGET_LOG To compile it as a module, choose M here. If unsure, say N. @@ -1850,24 +1517,35 @@ config NETFILTER_XT_TARGET_MARK tristate '"MARK" target support' depends on NETFILTER_ADVANCED ---- a/net/netfilter/Makefile 2018-04-22 23:18:25.711727410 -0400 -+++ b/net/netfilter/Makefile 2018-04-22 23:20:39.423768990 -0400 -@@ -136,6 +136,7 @@ - obj-$(CONFIG_NETFILTER_XT_TARGET_FLOWOFFLOAD) += xt_FLOWOFFLOAD.o +diff -Naupr linux-4.19.94_orig/net/netfilter/Makefile linux-4.19.94/net/netfilter/Makefile +--- linux-4.19.94_orig/net/netfilter/Makefile 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/net/netfilter/Makefile 2020-01-10 13:42:30.111018732 +0200 +@@ -142,6 +142,7 @@ obj-$(CONFIG_NETFILTER_XT_TARGET_CT) += + obj-$(CONFIG_NETFILTER_XT_TARGET_DSCP) += xt_DSCP.o obj-$(CONFIG_NETFILTER_XT_TARGET_HL) += xt_HL.o obj-$(CONFIG_NETFILTER_XT_TARGET_HMARK) += xt_HMARK.o +obj-$(CONFIG_NETFILTER_XT_TARGET_IMQ) += xt_IMQ.o obj-$(CONFIG_NETFILTER_XT_TARGET_LED) += xt_LED.o obj-$(CONFIG_NETFILTER_XT_TARGET_LOG) += xt_LOG.o obj-$(CONFIG_NETFILTER_XT_TARGET_NETMAP) += xt_NETMAP.o ---- a/net/netfilter/nf_queue.c 2018-04-22 23:18:25.699727407 -0400 -+++ b/net/netfilter/nf_queue.c 2018-04-22 23:22:59.395812579 -0400 -@@ -1,4 +1,4 @@ --/* -+ /* - * Rusty Russell (C)2000 -- This code is GPL. - * Patrick McHardy (c) 2006-2012 - */ +diff -Naupr linux-4.19.94_orig/net/netfilter/core.c linux-4.19.94/net/netfilter/core.c +--- linux-4.19.94_orig/net/netfilter/core.c 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/net/netfilter/core.c 2020-01-10 13:42:30.111018732 +0200 +@@ -518,6 +518,11 @@ int nf_hook_slow(struct sk_buff *skb, st + if (ret == 0) + ret = -EPERM; + return ret; ++ case NF_IMQ_QUEUE: ++ ret = nf_queue(skb, state, e, s, verdict); ++ if (ret == -ECANCELED) ++ continue; ++ return ret; + case NF_QUEUE: + ret = nf_queue(skb, state, e, s, verdict); + if (ret == 1) +diff -Naupr linux-4.19.94_orig/net/netfilter/nf_queue.c linux-4.19.94/net/netfilter/nf_queue.c +--- linux-4.19.94_orig/net/netfilter/nf_queue.c 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/net/netfilter/nf_queue.c 2020-01-10 13:49:09.686027527 +0200 @@ -29,6 +29,23 @@ * receives, no matter what. */ @@ -1892,7 +1570,7 @@ /* return EBUSY when somebody else is registered, return EEXIST if the * same handler is registered, return 0 in case of success. */ void nf_register_queue_handler(struct net *net, const struct nf_queue_handler *qh) -@@ -144,16 +161,29 @@ +@@ -141,16 +158,28 @@ static void nf_ip6_saveroute(const struc static int __nf_queue(struct sk_buff *skb, const struct nf_hook_state *state, const struct nf_hook_entries *entries, @@ -1909,13 +1587,12 @@ /* QUEUE == DROP if no one is waiting, to be safe. */ - qh = rcu_dereference(net->nf.queue_handler); -+ + if (queuetype == NF_IMQ_QUEUE) { +#if defined(CONFIG_IMQ) || defined(CONFIG_IMQ_MODULE) -+ qh = rcu_dereference(queue_imq_handler); ++ qh = rcu_dereference(queue_imq_handler); +#else -+ BUG(); -+ goto err_unlock; ++ BUG(); ++ goto err_unlock; +#endif + } else { + qh = rcu_dereference(net->nf.queue_handler); @@ -1924,7 +1601,7 @@ if (!qh) { status = -ESRCH; goto err; -@@ -217,8 +248,16 @@ +@@ -218,8 +247,16 @@ int nf_queue(struct sk_buff *skb, struct { int ret; @@ -1942,7 +1619,7 @@ if (ret == -ESRCH && (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS)) return 1; -@@ -302,6 +341,7 @@ +@@ -323,6 +360,7 @@ next_hook: local_bh_enable(); break; case NF_QUEUE: @@ -1950,8 +1627,9 @@ err = nf_queue(skb, &entry->state, hooks, i, verdict); if (err == 1) goto next_hook; ---- /dev/null 2018-03-30 15:39:24.291451107 -0400 -+++ b/net/netfilter/xt_IMQ.c 2018-04-22 23:20:39.423768990 -0400 +diff -Naupr linux-4.19.94_orig/net/netfilter/xt_IMQ.c linux-4.19.94/net/netfilter/xt_IMQ.c +--- linux-4.19.94_orig/net/netfilter/xt_IMQ.c 1970-01-01 02:00:00.000000000 +0200 ++++ linux-4.19.94/net/netfilter/xt_IMQ.c 2020-01-10 13:42:30.112018732 +0200 @@ -0,0 +1,72 @@ +/* + * This target marks packets to be enqueued to an imq device @@ -2025,9 +1703,10 @@ +MODULE_ALIAS("ipt_IMQ"); +MODULE_ALIAS("ip6t_IMQ"); + ---- a/net/sched/sch_generic.c 2018-04-22 23:18:26.623727693 -0400 -+++ b/net/sched/sch_generic.c 2018-04-22 23:20:39.423768990 -0400 -@@ -158,6 +158,14 @@ +diff -Naupr linux-4.19.94_orig/net/sched/sch_generic.c linux-4.19.94/net/sched/sch_generic.c +--- linux-4.19.94_orig/net/sched/sch_generic.c 2020-01-09 11:19:10.000000000 +0200 ++++ linux-4.19.94/net/sched/sch_generic.c 2020-01-10 13:42:30.112018732 +0200 +@@ -292,6 +292,14 @@ trace: return skb; } @@ -2041,4 +1720,4 @@ + /* * Transmit possibly several skbs, and handle the return status as - * required. Owning running seqcount bit guarantees that \ No newline at end of file + * required. Owning running seqcount bit guarantees that