DF-0735 / fix.diff
diff --git a/sys/netgraph7/ng_ipfw.c b/sys/netgraph7/ng_ipfw.c --- a/sys/netgraph7/ng_ipfw.c +++ b/sys/netgraph7/ng_ipfw.c @@ -37,6 +37,8 @@ #include <sys/syslog.h> #include <net/if.h> +#include <net/netisr.h> +#include <net/netmsg2.h> #include <netinet/in.h> #include <netinet/in_systm.h> @@ -62,6 +64,9 @@ static hook_p ng_ipfw_findhook1(node_p, u_int16_t ); static int ng_ipfw_input(struct mbuf **, int, struct ip_fw_args *, int); +/* DF-0735 fix: ip_output() requires netisr thread context + * (ASSERT_NETISR_NCPUS at ip_output.c:185); this netmsg handler runs there. */ +static void ng_ipfw_ip_output_dispatch(netmsg_t nmsg); /* We have only one node */ static node_p fw_node; @@ -216,6 +221,21 @@ } +/* + * DF-0735 fix: netmsg handler that runs ip_output() from a netisr thread. + * ip_output() opens with ASSERT_NETISR_NCPUS(mycpuid) (ip_output.c:185); + * this callback is dispatched from ng_ipfw_rcvdata via lwkt_sendmsg to a + * netisr port so the assertion holds. Pattern matches dummynet's + * ip_dn_ip_output at sys/net/dummynet/ip_dummynet_glue.c:270. + */ +static void +ng_ipfw_ip_output_dispatch(netmsg_t nmsg) +{ + struct mbuf *m = nmsg->packet.nm_packet; + + ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); +} + static int ng_ipfw_rcvdata(hook_p hook, item_p item) { @@ -233,20 +253,36 @@ switch (ngit->dir) { case NG_IPFW_OUT: + /* + * DF-0735: do NOT call ip_output() directly -- this rcvdata runs + * in the netgraph worker thread (created at ng_base.c:2787-2789), + * which is NOT a netisr thread, so ip_output.c:185's + * ASSERT_NETISR_NCPUS(mycpuid) would panic on default-GENERIC + * (INVARIANTS ON). Dispatch the mbuf to a netisr port and call + * ip_output from there, mirroring dummynet's ip_dn_queue pattern + * (sys/net/dummynet/ip_dummynet_glue.c:82-99). + */ { - struct ip *ip; + struct netmsg_packet *nmp; - if (m->m_len < sizeof(struct ip) && - (m = m_pullup(m, sizeof(struct ip))) == NULL) - return (EINVAL); - - ip = mtod(m, struct ip *); - - return ip_output(m, NULL, NULL, IP_FORWARDING, NULL, NULL); + nmp = &m->m_hdr.mh_netmsg; + netmsg_init(&nmp->base, NULL, &netisr_apanic_rport, + 0, ng_ipfw_ip_output_dispatch); + nmp->nm_packet = m; + lwkt_sendmsg(netisr_cpuport(mycpuid), &nmp->base.lmsg); + return (0); } case NG_IPFW_IN: - ip_input(m); - return (0); + /* + * DF-0735: do NOT call ip_input() directly. Hand the packet to + * NETISR_IP via netisr_queue(), as the sibling ng_ip_input.c:125 + * does. ip_input() at ip_input.c:460 opens with + * ASSERT_NETISR_NCPUS(mycpuid) and must be called from a netisr + * thread. + */ + m->m_flags &= ~M_HASH; + netisr_queue(NETISR_IP, m); + return (0); default: panic("ng_ipfw_rcvdata: bad dir %u", ngit->dir); } |