Hello,
patch below introduces ip_send() function to OpenBSD kernel. ip_send()
function takes an mbuf with packet and passes to ip_output(), which
will be running in softnet task.
the patch also changes icmp_error()/icmp6_error() to dispatch the ICMP error
responses via ip_send(), so both functions are safe for MP friendly PF, because
pf_test() recursion is avoided.
the overall idea comes from Markus Friedl, some fine tuning touches suches
using mbuf queue come from mikeb.
the ipsend_mq queue size is 64 currently. I need some guidance if it is
too much/too little. I've just opted for nice rounded number.
OK?
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 14:00:16 -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.955
diff -u -p -r1.955 pf.c
--- net/pf.c 3 Dec 2015 09:49:15 -0000 1.955
+++ net/pf.c 3 Dec 2015 14:00:16 -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 14:00:16 -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.263
diff -u -p -r1.263 ip_input.c
--- netinet/ip_input.c 2 Dec 2015 13:29:26 -0000 1.263
+++ netinet/ip_input.c 3 Dec 2015 14:00:16 -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,11 +122,15 @@ 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);
void ip_forward(struct mbuf *, struct ifnet *, int);
+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
@@ -184,6 +189,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;
@@ -1742,3 +1749,18 @@ ip_savecontrol(struct inpcb *inp, struct
}
}
+static void
+ip_send_dispatch(void *cx)
+{
+ struct mbuf *m;
+
+ while ((m = mq_dequeue((struct mbuf_queue *)cx)) != NULL)
+ ip_output(m, NULL, NULL, 0, NULL, NULL, 0);
+}
+
+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 14:00:16 -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 *
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 14:00:16 -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 14:00:16 -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>
@@ -123,6 +124,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 +155,8 @@ ip6_init(void)
nd6_init();
frag6_init();
ip6_init2((void *)0);
+
+ mq_init(&ip6send_mq, 64, IPL_SOFTNET);
}
void
@@ -1430,4 +1438,20 @@ ip6_sysctl(int *name, u_int namelen, voi
return (EOPNOTSUPP);
}
/* NOTREACHED */
+}
+
+static void
+ip6_send_dispatch(void *cx)
+{
+ struct mbuf *m;
+
+ while ((m = mq_dequeue((struct mbuf_queue *)cx)) != NULL)
+ ip6_output(m, NULL, NULL, IPV6_MINMTU, NULL, NULL);
+}
+
+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 14:00:16 -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);