Hello, so after a feedback in a hackroom here is the third version of patch. The summary of changes is as follows: - ip*_send() function use softnettq to dispatch packet - ip*_output() functions running in ip*_send_dispatch() are protected KERNEL_LOCK() and running at SOFTNET spl level. - mq_delist() is used to move packets from global queue to local queue for processing.
regards sasha --------8<---------------8<---------------8<------------------8<-------- Index: net/if.h =================================================================== RCS file: /cvs/src/sys/net/if.h,v retrieving revision 1.174 diff -u -p -r1.174 if.h --- net/if.h 3 Dec 2015 12:22:51 -0000 1.174 +++ net/if.h 3 Dec 2015 17:06:32 -0000 @@ -484,4 +484,7 @@ int if_setlladdr(struct ifnet *, const u #endif /* __BSD_VISIBLE */ +#ifdef _KERNEL +extern struct taskq *softnettq; +#endif /* _KERNEL */ #endif /* _NET_IF_H_ */ Index: net/pf.c =================================================================== RCS file: /cvs/src/sys/net/pf.c,v retrieving revision 1.956 diff -u -p -r1.956 pf.c --- net/pf.c 3 Dec 2015 14:05:28 -0000 1.956 +++ net/pf.c 3 Dec 2015 17:06:32 -0000 @@ -2424,11 +2424,11 @@ pf_send_tcp(const struct pf_rule *r, sa_ switch (af) { case AF_INET: - ip_output(m, NULL, NULL, 0, NULL, NULL, 0); + ip_send(m); break; #ifdef INET6 case AF_INET6: - ip6_output(m, NULL, NULL, 0, NULL, NULL); + ip6_send(m); break; #endif /* INET6 */ } Index: netinet/ip_icmp.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_icmp.c,v retrieving revision 1.149 diff -u -p -r1.149 ip_icmp.c --- netinet/ip_icmp.c 2 Dec 2015 16:35:53 -0000 1.149 +++ netinet/ip_icmp.c 3 Dec 2015 17:06:33 -0000 @@ -854,7 +854,10 @@ icmp_send(struct mbuf *m, struct mbuf *o printf("icmp_send dst %s src %s\n", dst, src); } #endif - ip_output(m, opts, NULL, 0, NULL, NULL, 0); + if (opts != NULL) + m = ip_insertoptions(m, opts, &hlen); + + ip_send(m); } u_int32_t Index: netinet/ip_input.c =================================================================== RCS file: /cvs/src/sys/netinet/ip_input.c,v retrieving revision 1.264 diff -u -p -r1.264 ip_input.c --- netinet/ip_input.c 3 Dec 2015 15:12:59 -0000 1.264 +++ netinet/ip_input.c 3 Dec 2015 17:06:33 -0000 @@ -44,6 +44,7 @@ #include <sys/socketvar.h> #include <sys/sysctl.h> #include <sys/pool.h> +#include <sys/task.h> #include <net/if.h> #include <net/if_var.h> @@ -121,6 +122,8 @@ struct pool ipq_pool; struct ipstat ipstat; +static struct mbuf_queue ipsend_mq; + void ip_ours(struct mbuf *); int ip_dooptions(struct mbuf *, struct ifnet *); int in_ouraddr(struct mbuf *, struct ifnet *, struct in_addr); @@ -130,6 +133,8 @@ int ip_input_ipsec_fwd_check(struct mbuf int ip_input_ipsec_ours_check(struct mbuf *, int); #endif /* IPSEC */ +static void ip_send_dispatch(void *); +static struct task ipsend_task = TASK_INITIALIZER(ip_send_dispatch, &ipsend_mq); /* * Used to save the IP options in case a protocol wants to respond * to an incoming packet over the same route if the packet got here @@ -188,6 +193,8 @@ ip_init(void) strlcpy(ipsec_def_enc, IPSEC_DEFAULT_DEF_ENC, sizeof(ipsec_def_enc)); strlcpy(ipsec_def_auth, IPSEC_DEFAULT_DEF_AUTH, sizeof(ipsec_def_auth)); strlcpy(ipsec_def_comp, IPSEC_DEFAULT_DEF_COMP, sizeof(ipsec_def_comp)); + + mq_init(&ipsend_mq, 64, IPL_SOFTNET); } struct route ipforward_rt; @@ -1752,3 +1759,26 @@ ip_savecontrol(struct inpcb *inp, struct } } +static void +ip_send_dispatch(void *cx) +{ + struct mbuf *m; + struct mbuf_list ml; + int s; + + mq_delist((struct mbuf_queue *)cx, &ml); + s = splsoftnet(); + KERNEL_LOCK(); + while ((m = ml_dequeue(&ml)) != NULL) { + ip_output(m, NULL, NULL, 0, NULL, NULL, 0); + } + KERNEL_UNLOCK(); + splx(s); +} + +void +ip_send(struct mbuf *m) +{ + mq_enqueue(&ipsend_mq, m); + task_add(softnettq, &ipsend_task); +} Index: netinet/ip_var.h =================================================================== RCS file: /cvs/src/sys/netinet/ip_var.h,v retrieving revision 1.60 diff -u -p -r1.60 ip_var.h --- netinet/ip_var.h 16 Jul 2015 21:14:21 -0000 1.60 +++ netinet/ip_var.h 3 Dec 2015 17:06:33 -0000 @@ -180,6 +180,8 @@ void ip_freef(struct ipq *); void ip_freemoptions(struct ip_moptions *); int ip_getmoptions(int, struct ip_moptions *, struct mbuf **); void ip_init(void); +struct mbuf* + ip_insertoptions(struct mbuf *, struct mbuf *, int *); int ip_mforward(struct mbuf *, struct ifnet *); int ip_optcopy(struct ip *, struct ip *); int ip_output(struct mbuf *, struct mbuf *, struct route *, int, @@ -191,6 +193,7 @@ struct in_ifaddr * ip_rtaddr(struct in_addr, u_int); u_int16_t ip_randomid(void); +void ip_send(struct mbuf *); int ip_setmoptions(int, struct ip_moptions **, struct mbuf *, u_int); void ip_slowtimo(void); struct mbuf * @@ -207,5 +210,6 @@ void rip_input(struct mbuf *, ...); int rip_output(struct mbuf *, ...); int rip_usrreq(struct socket *, int, struct mbuf *, struct mbuf *, struct mbuf *, struct proc *); + #endif /* _KERNEL */ #endif /* _NETINET_IP_VAR_H_ */ Index: netinet6/icmp6.c =================================================================== RCS file: /cvs/src/sys/netinet6/icmp6.c,v retrieving revision 1.181 diff -u -p -r1.181 icmp6.c --- netinet6/icmp6.c 2 Dec 2015 16:35:53 -0000 1.181 +++ netinet6/icmp6.c 3 Dec 2015 17:06:33 -0000 @@ -1302,7 +1302,7 @@ icmp6_reflect(struct mbuf *m, size_t off #if NPF > 0 pf_pkt_addr_changed(m); #endif - ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL); + ip6_send(m); return; bad: Index: netinet6/ip6_input.c =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_input.c,v retrieving revision 1.151 diff -u -p -r1.151 ip6_input.c --- netinet6/ip6_input.c 11 Nov 2015 10:23:23 -0000 1.151 +++ netinet6/ip6_input.c 3 Dec 2015 17:06:33 -0000 @@ -77,6 +77,7 @@ #include <sys/timeout.h> #include <sys/kernel.h> #include <sys/syslog.h> +#include <sys/task.h> #include <net/if.h> #include <net/if_var.h> @@ -89,6 +90,7 @@ #include <netinet/ip.h> #include <netinet/in_pcb.h> +#include <netinet/ip_var.h> #include <netinet6/in6_var.h> #include <netinet/ip6.h> #include <netinet6/ip6_var.h> @@ -123,6 +125,11 @@ int ip6_check_rh0hdr(struct mbuf *, int int ip6_hopopts_input(u_int32_t *, u_int32_t *, struct mbuf **, int *); struct mbuf *ip6_pullexthdr(struct mbuf *, size_t, int); +static struct mbuf_queue ip6send_mq; + +static void ip6_send_dispatch(void *); +static struct task ip6send_task = TASK_INITIALIZER(ip6_send_dispatch, &ip6send_mq); + /* * IP6 initialization: fill in IP6 protocol switch table. * All protocols not implemented in kernel go to raw IP6 protocol handler. @@ -149,6 +156,8 @@ ip6_init(void) nd6_init(); frag6_init(); ip6_init2((void *)0); + + mq_init(&ip6send_mq, 64, IPL_SOFTNET); } void @@ -1430,4 +1439,28 @@ ip6_sysctl(int *name, u_int namelen, voi return (EOPNOTSUPP); } /* NOTREACHED */ +} + +static void +ip6_send_dispatch(void *cx) +{ + struct mbuf *m; + struct mbuf_list ml; + int s; + + mq_delist((struct mbuf_queue *)cx, &ml); + s = splsoftnet(); + KERNEL_LOCK(); + while ((m = ml_dequeue(&ml)) != NULL) { + ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL); + } + KERNEL_UNLOCK(); + splx(s); +} + +void +ip6_send(struct mbuf *m) +{ + mq_enqueue(&ip6send_mq, m); + task_add(softnettq, &ip6send_task); } Index: netinet6/ip6_var.h =================================================================== RCS file: /cvs/src/sys/netinet6/ip6_var.h,v retrieving revision 1.56 diff -u -p -r1.56 ip6_var.h --- netinet6/ip6_var.h 25 Oct 2015 14:43:06 -0000 1.56 +++ netinet6/ip6_var.h 3 Dec 2015 17:06:33 -0000 @@ -275,6 +275,7 @@ int ip6_setpktopts(struct mbuf *, struct void ip6_clearpktopts(struct ip6_pktopts *, int); void ip6_randomid_init(void); u_int32_t ip6_randomid(void); +void ip6_send(struct mbuf *); int route6_input(struct mbuf **, int *, int);