xref: /dragonfly/tools/tools/netrate/pktgen/pktgen.c (revision 2b3f93ea)
14fa8e46eSSepherosa Ziehau /*
2391741ecSSepherosa Ziehau  * Copyright (c) 2012 The DragonFly Project.  All rights reserved.
34fa8e46eSSepherosa Ziehau  *
44fa8e46eSSepherosa Ziehau  * This code is derived from software contributed to The DragonFly Project
54fa8e46eSSepherosa Ziehau  * by Sepherosa Ziehau <sepherosa@gmail.com>
64fa8e46eSSepherosa Ziehau  *
74fa8e46eSSepherosa Ziehau  * Redistribution and use in source and binary forms, with or without
84fa8e46eSSepherosa Ziehau  * modification, are permitted provided that the following conditions
94fa8e46eSSepherosa Ziehau  * are met:
104fa8e46eSSepherosa Ziehau  *
114fa8e46eSSepherosa Ziehau  * 1. Redistributions of source code must retain the above copyright
124fa8e46eSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer.
134fa8e46eSSepherosa Ziehau  * 2. Redistributions in binary form must reproduce the above copyright
144fa8e46eSSepherosa Ziehau  *    notice, this list of conditions and the following disclaimer in
154fa8e46eSSepherosa Ziehau  *    the documentation and/or other materials provided with the
164fa8e46eSSepherosa Ziehau  *    distribution.
174fa8e46eSSepherosa Ziehau  * 3. Neither the name of The DragonFly Project nor the names of its
184fa8e46eSSepherosa Ziehau  *    contributors may be used to endorse or promote products derived
194fa8e46eSSepherosa Ziehau  *    from this software without specific, prior written permission.
204fa8e46eSSepherosa Ziehau  *
214fa8e46eSSepherosa Ziehau  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
224fa8e46eSSepherosa Ziehau  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
234fa8e46eSSepherosa Ziehau  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
244fa8e46eSSepherosa Ziehau  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
254fa8e46eSSepherosa Ziehau  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
264fa8e46eSSepherosa Ziehau  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
274fa8e46eSSepherosa Ziehau  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
284fa8e46eSSepherosa Ziehau  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
294fa8e46eSSepherosa Ziehau  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
304fa8e46eSSepherosa Ziehau  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
314fa8e46eSSepherosa Ziehau  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
324fa8e46eSSepherosa Ziehau  * SUCH DAMAGE.
334fa8e46eSSepherosa Ziehau  */
344fa8e46eSSepherosa Ziehau 
354fa8e46eSSepherosa Ziehau #define _IP_VHL
364fa8e46eSSepherosa Ziehau 
374fa8e46eSSepherosa Ziehau #include <sys/param.h>
384fa8e46eSSepherosa Ziehau #include <sys/conf.h>
394fa8e46eSSepherosa Ziehau #include <sys/device.h>
404fa8e46eSSepherosa Ziehau #include <sys/in_cksum.h>
414fa8e46eSSepherosa Ziehau #include <sys/kernel.h>
424fa8e46eSSepherosa Ziehau #include <sys/malloc.h>
434fa8e46eSSepherosa Ziehau #include <sys/mbuf.h>
444fa8e46eSSepherosa Ziehau #include <sys/proc.h>
45*2b3f93eaSMatthew Dillon #include <sys/caps.h>
46391741ecSSepherosa Ziehau #include <sys/queue.h>
474fa8e46eSSepherosa Ziehau #include <sys/socket.h>
484fa8e46eSSepherosa Ziehau #include <sys/systm.h>
494fa8e46eSSepherosa Ziehau #include <sys/serialize.h>
504fa8e46eSSepherosa Ziehau 
514fa8e46eSSepherosa Ziehau #include <net/if.h>
524fa8e46eSSepherosa Ziehau #include <net/if_dl.h>
534fa8e46eSSepherosa Ziehau #include <net/if_var.h>
544fa8e46eSSepherosa Ziehau #include <net/ifq_var.h>
554fa8e46eSSepherosa Ziehau #include <net/ethernet.h>
56391741ecSSepherosa Ziehau #include <net/netmsg2.h>
575337421cSSepherosa Ziehau #include <net/netisr2.h>
584fa8e46eSSepherosa Ziehau 
594fa8e46eSSepherosa Ziehau #include <netinet/in.h>
609064712fSSepherosa Ziehau #include <netinet/in_pcb.h>
614fa8e46eSSepherosa Ziehau #include <netinet/ip.h>
624fa8e46eSSepherosa Ziehau #include <netinet/udp_var.h>
634fa8e46eSSepherosa Ziehau 
644fa8e46eSSepherosa Ziehau #include "pktgen.h"
654fa8e46eSSepherosa Ziehau 
664fa8e46eSSepherosa Ziehau #define CDEV_NAME	"pktg"
674fa8e46eSSepherosa Ziehau 
68391741ecSSepherosa Ziehau #define PKTGEN_BUFSZ	2048
69391741ecSSepherosa Ziehau 
70390d8a05SSepherosa Ziehau #ifndef PKTGEN_DEVCNT
71390d8a05SSepherosa Ziehau #define PKTGEN_DEVCNT	4
72390d8a05SSepherosa Ziehau #endif
73390d8a05SSepherosa Ziehau 
74391741ecSSepherosa Ziehau struct pktgen;
75391741ecSSepherosa Ziehau 
76b0cd2b4bSSepherosa Ziehau struct netmsg_pktgen {
77b0cd2b4bSSepherosa Ziehau 	struct netmsg_base	np_base;
78b0cd2b4bSSepherosa Ziehau 	struct pktgen		*np_pktg;
79b0cd2b4bSSepherosa Ziehau 	struct ifaltq_subque	*np_ifsq;
80b0cd2b4bSSepherosa Ziehau };
81b0cd2b4bSSepherosa Ziehau 
82391741ecSSepherosa Ziehau struct pktgen_buf {
83391741ecSSepherosa Ziehau 	struct netmsg_base	pb_nmsg;	/* MUST BE THE FIRST */
84391741ecSSepherosa Ziehau 	void			*pb_buf;
85391741ecSSepherosa Ziehau 	volatile int		pb_done;
864c9906cbSSepherosa Ziehau 	int			pb_inuse;
87391741ecSSepherosa Ziehau 	struct ifnet		*pb_ifp;
882fb36fabSSepherosa Ziehau 	struct ifaltq_subque	*pb_ifsq;
89391741ecSSepherosa Ziehau 	int			pb_len;
90391741ecSSepherosa Ziehau 	int			pb_cpuid;
91391741ecSSepherosa Ziehau 	struct pktgen		*pb_pktg;
92391741ecSSepherosa Ziehau 	LIST_ENTRY(pktgen_buf)	pb_link;
93391741ecSSepherosa Ziehau };
94391741ecSSepherosa Ziehau 
951bbaa2adSSepherosa Ziehau struct pktgen_pcpu {
961bbaa2adSSepherosa Ziehau 	struct callout		pktg_stop;
971bbaa2adSSepherosa Ziehau 	LIST_HEAD(, pktgen_buf)	pktg_buflist;
981bbaa2adSSepherosa Ziehau };
991bbaa2adSSepherosa Ziehau 
1004fa8e46eSSepherosa Ziehau struct pktgen {
1014fa8e46eSSepherosa Ziehau 	uint32_t		pktg_flags;	/* PKTG_F_ */
1024fa8e46eSSepherosa Ziehau 	int			pktg_refcnt;
1034fa8e46eSSepherosa Ziehau 
1044fa8e46eSSepherosa Ziehau 	int			pktg_duration;
1054fa8e46eSSepherosa Ziehau 
1064fa8e46eSSepherosa Ziehau 	int			pktg_datalen;
1074fa8e46eSSepherosa Ziehau 	struct ifnet		*pktg_ifp;
108c95ebcd6SSepherosa Ziehau 
109793f802fSSepherosa Ziehau 	int			pktg_pktenq;
110793f802fSSepherosa Ziehau 
111391741ecSSepherosa Ziehau 	struct sockaddr_in	pktg_src;
112391741ecSSepherosa Ziehau 	int			pktg_ndst;
113391741ecSSepherosa Ziehau 	struct sockaddr_in	*pktg_dst;
1144fa8e46eSSepherosa Ziehau 	uint8_t			pktg_dst_lladdr[ETHER_ADDR_LEN];
115391741ecSSepherosa Ziehau 
1161bbaa2adSSepherosa Ziehau 	struct pktgen_pcpu	pktg_pcpu[MAXCPU];
1174fa8e46eSSepherosa Ziehau };
1184fa8e46eSSepherosa Ziehau 
1194fa8e46eSSepherosa Ziehau #define PKTG_F_CONFIG		0x1
1204fa8e46eSSepherosa Ziehau #define PKTG_F_RUNNING		0x4
121eec66bd4SSepherosa Ziehau #define PKTG_F_SWITCH_SRCDST	0x8
1224fa8e46eSSepherosa Ziehau 
1234fa8e46eSSepherosa Ziehau static int 		pktgen_modevent(module_t, int, void *);
124391741ecSSepherosa Ziehau 
125391741ecSSepherosa Ziehau static void		pktgen_buf_free(void *);
126391741ecSSepherosa Ziehau static void		pktgen_buf_ref(void *);
127391741ecSSepherosa Ziehau static void		pktgen_buf_send(netmsg_t);
128391741ecSSepherosa Ziehau 
1294fa8e46eSSepherosa Ziehau static int		pktgen_config(struct pktgen *,
1304fa8e46eSSepherosa Ziehau 			    const struct pktgen_conf *);
131b0cd2b4bSSepherosa Ziehau static int		pktgen_start(struct pktgen *, int);
132391741ecSSepherosa Ziehau static void		pktgen_free(struct pktgen *);
133c6830078SSepherosa Ziehau static void		pktgen_ref(struct pktgen *);
1341bbaa2adSSepherosa Ziehau static void		pktgen_pcpu_stop_cb(void *);
135391741ecSSepherosa Ziehau static void		pktgen_mbuf(struct pktgen_buf *, struct mbuf *);
136b0cd2b4bSSepherosa Ziehau static void		pktgen_start_ifsq(struct pktgen *,
137b0cd2b4bSSepherosa Ziehau 			    struct ifaltq_subque *);
138b0cd2b4bSSepherosa Ziehau static void		pktgen_start_ifsq_handler(netmsg_t);
1394fa8e46eSSepherosa Ziehau 
1404fa8e46eSSepherosa Ziehau static d_open_t		pktgen_open;
1414fa8e46eSSepherosa Ziehau static d_close_t	pktgen_close;
1424fa8e46eSSepherosa Ziehau static d_ioctl_t	pktgen_ioctl;
1434fa8e46eSSepherosa Ziehau 
1444fa8e46eSSepherosa Ziehau static struct dev_ops	pktgen_ops = {
145624409c2SSepherosa Ziehau 	{ CDEV_NAME, 0, D_MPSAFE },
1464fa8e46eSSepherosa Ziehau 	.d_open =	pktgen_open,
1474fa8e46eSSepherosa Ziehau 	.d_close =	pktgen_close,
1484fa8e46eSSepherosa Ziehau 	.d_ioctl =	pktgen_ioctl,
1494fa8e46eSSepherosa Ziehau };
1504fa8e46eSSepherosa Ziehau 
1514c9906cbSSepherosa Ziehau static volatile int		pktgen_refcnt;
152e3d0d8d7SSepherosa Ziehau static struct lwkt_token pktgen_tok = LWKT_TOKEN_INITIALIZER(pktgen_token);
1534fa8e46eSSepherosa Ziehau 
1544fa8e46eSSepherosa Ziehau MALLOC_DECLARE(M_PKTGEN);
1554fa8e46eSSepherosa Ziehau MALLOC_DEFINE(M_PKTGEN, CDEV_NAME, "Packet generator");
1564fa8e46eSSepherosa Ziehau 
1574fa8e46eSSepherosa Ziehau DEV_MODULE(pktgen, pktgen_modevent, NULL);
1584fa8e46eSSepherosa Ziehau 
1594fa8e46eSSepherosa Ziehau static int
pktgen_modevent(module_t mod,int type,void * data)1604fa8e46eSSepherosa Ziehau pktgen_modevent(module_t mod, int type, void *data)
1614fa8e46eSSepherosa Ziehau {
162390d8a05SSepherosa Ziehau 	int error = 0, i;
1634fa8e46eSSepherosa Ziehau 
1644fa8e46eSSepherosa Ziehau 	switch (type) {
1654fa8e46eSSepherosa Ziehau 	case MOD_LOAD:
166390d8a05SSepherosa Ziehau 		for (i = 0; i < PKTGEN_DEVCNT; ++i) {
1674b3b3198SAlex Hornung 			make_dev(&pktgen_ops, 0, UID_ROOT, GID_WHEEL, 0600,
168390d8a05SSepherosa Ziehau 			    CDEV_NAME"%d", i);
169390d8a05SSepherosa Ziehau 		}
1704fa8e46eSSepherosa Ziehau 		break;
1714fa8e46eSSepherosa Ziehau 
1724fa8e46eSSepherosa Ziehau 	case MOD_UNLOAD:
1734fa8e46eSSepherosa Ziehau 		if (pktgen_refcnt > 0)
1744fa8e46eSSepherosa Ziehau 			return EBUSY;
1754b3b3198SAlex Hornung 		dev_ops_remove_all(&pktgen_ops);
1764fa8e46eSSepherosa Ziehau 		break;
1774fa8e46eSSepherosa Ziehau 
1784fa8e46eSSepherosa Ziehau 	default:
1794fa8e46eSSepherosa Ziehau 		error = EOPNOTSUPP;
1804fa8e46eSSepherosa Ziehau 		break;
1814fa8e46eSSepherosa Ziehau 	}
1824fa8e46eSSepherosa Ziehau 	return error;
1834fa8e46eSSepherosa Ziehau }
1844fa8e46eSSepherosa Ziehau 
1854fa8e46eSSepherosa Ziehau static int
pktgen_open(struct dev_open_args * ap)1864fa8e46eSSepherosa Ziehau pktgen_open(struct dev_open_args *ap)
1874fa8e46eSSepherosa Ziehau {
1884fa8e46eSSepherosa Ziehau 	cdev_t dev = ap->a_head.a_dev;
1894fa8e46eSSepherosa Ziehau 	struct pktgen *pktg;
1901bbaa2adSSepherosa Ziehau 	int error, i;
1914fa8e46eSSepherosa Ziehau 
1929eaf083fSSascha Wildner 	error = priv_check_cred(ap->a_cred, PRIV_ROOT, 0);
1934fa8e46eSSepherosa Ziehau 	if (error)
1944fa8e46eSSepherosa Ziehau 		return error;
1954fa8e46eSSepherosa Ziehau 
196e3d0d8d7SSepherosa Ziehau 	lwkt_gettoken(&pktgen_tok);
1974fa8e46eSSepherosa Ziehau 
1984fa8e46eSSepherosa Ziehau 	if (dev->si_drv1 != NULL) {
199e3d0d8d7SSepherosa Ziehau 		lwkt_reltoken(&pktgen_tok);
2004fa8e46eSSepherosa Ziehau 		return EBUSY;
2014fa8e46eSSepherosa Ziehau 	}
2024fa8e46eSSepherosa Ziehau 
2034fa8e46eSSepherosa Ziehau 	pktg = kmalloc(sizeof(*pktg), M_PKTGEN, M_ZERO | M_WAITOK);
2041bbaa2adSSepherosa Ziehau 	for (i = 0; i < ncpus; ++i) {
2051bbaa2adSSepherosa Ziehau 		struct pktgen_pcpu *p = &pktg->pktg_pcpu[i];
2061bbaa2adSSepherosa Ziehau 
2071bbaa2adSSepherosa Ziehau 		callout_init_mp(&p->pktg_stop);
2081bbaa2adSSepherosa Ziehau 		LIST_INIT(&p->pktg_buflist);
2091bbaa2adSSepherosa Ziehau 	}
2104fa8e46eSSepherosa Ziehau 
2114fa8e46eSSepherosa Ziehau 	dev->si_drv1 = pktg;
2124fa8e46eSSepherosa Ziehau 	pktg->pktg_refcnt = 1;
2134fa8e46eSSepherosa Ziehau 
2144c9906cbSSepherosa Ziehau 	atomic_add_int(&pktgen_refcnt, 1);
2154fa8e46eSSepherosa Ziehau 
216e3d0d8d7SSepherosa Ziehau 	lwkt_reltoken(&pktgen_tok);
2174fa8e46eSSepherosa Ziehau 	return 0;
2184fa8e46eSSepherosa Ziehau }
2194fa8e46eSSepherosa Ziehau 
2204fa8e46eSSepherosa Ziehau static int
pktgen_close(struct dev_close_args * ap)2214fa8e46eSSepherosa Ziehau pktgen_close(struct dev_close_args *ap)
2224fa8e46eSSepherosa Ziehau {
2234fa8e46eSSepherosa Ziehau 	cdev_t dev = ap->a_head.a_dev;
2244fa8e46eSSepherosa Ziehau 	struct pktgen *pktg = dev->si_drv1;
2254fa8e46eSSepherosa Ziehau 
226e3d0d8d7SSepherosa Ziehau 	lwkt_gettoken(&pktgen_tok);
2274fa8e46eSSepherosa Ziehau 	dev->si_drv1 = NULL;
228e3d0d8d7SSepherosa Ziehau 	lwkt_reltoken(&pktgen_tok);
229391741ecSSepherosa Ziehau 
2304c9906cbSSepherosa Ziehau 	pktgen_free(pktg);
2314c9906cbSSepherosa Ziehau 
2324fa8e46eSSepherosa Ziehau 	return 0;
2334fa8e46eSSepherosa Ziehau }
2344fa8e46eSSepherosa Ziehau 
2354fa8e46eSSepherosa Ziehau static int
pktgen_ioctl(struct dev_ioctl_args * ap __unused)2364fa8e46eSSepherosa Ziehau pktgen_ioctl(struct dev_ioctl_args *ap __unused)
2374fa8e46eSSepherosa Ziehau {
2384fa8e46eSSepherosa Ziehau 	cdev_t dev = ap->a_head.a_dev;
2394fa8e46eSSepherosa Ziehau 	caddr_t data = ap->a_data;
2404fa8e46eSSepherosa Ziehau 	struct pktgen *pktg = dev->si_drv1;
2414fa8e46eSSepherosa Ziehau 	int error;
2424fa8e46eSSepherosa Ziehau 
243e3d0d8d7SSepherosa Ziehau 	lwkt_gettoken(&pktgen_tok);
2444fa8e46eSSepherosa Ziehau 
2454fa8e46eSSepherosa Ziehau 	switch (ap->a_cmd) {
2464fa8e46eSSepherosa Ziehau 	case PKTGENSTART:
247b0cd2b4bSSepherosa Ziehau 		error = pktgen_start(pktg, 0);
248b0cd2b4bSSepherosa Ziehau 		break;
249b0cd2b4bSSepherosa Ziehau 
250b0cd2b4bSSepherosa Ziehau 	case PKTGENMQSTART:
251b0cd2b4bSSepherosa Ziehau 		error = pktgen_start(pktg, 1);
2524fa8e46eSSepherosa Ziehau 		break;
2534fa8e46eSSepherosa Ziehau 
2544fa8e46eSSepherosa Ziehau 	case PKTGENSCONF:
2554fa8e46eSSepherosa Ziehau 		error = pktgen_config(pktg, (const struct pktgen_conf *)data);
2564fa8e46eSSepherosa Ziehau 		break;
2574fa8e46eSSepherosa Ziehau 
2584fa8e46eSSepherosa Ziehau 	default:
2594fa8e46eSSepherosa Ziehau 		error = EOPNOTSUPP;
2604fa8e46eSSepherosa Ziehau 		break;
2614fa8e46eSSepherosa Ziehau 	}
2624fa8e46eSSepherosa Ziehau 
263e3d0d8d7SSepherosa Ziehau 	lwkt_reltoken(&pktgen_tok);
2644fa8e46eSSepherosa Ziehau 	return error;
2654fa8e46eSSepherosa Ziehau }
2664fa8e46eSSepherosa Ziehau 
2674fa8e46eSSepherosa Ziehau static int
pktgen_config(struct pktgen * pktg,const struct pktgen_conf * conf)2684fa8e46eSSepherosa Ziehau pktgen_config(struct pktgen *pktg, const struct pktgen_conf *conf)
2694fa8e46eSSepherosa Ziehau {
2704fa8e46eSSepherosa Ziehau 	const struct sockaddr_in *sin;
271391741ecSSepherosa Ziehau 	struct sockaddr_in *dst = NULL;
2724fa8e46eSSepherosa Ziehau 	const struct sockaddr *sa;
2734fa8e46eSSepherosa Ziehau 	struct ifnet *ifp;
274391741ecSSepherosa Ziehau 	size_t dst_size;
275793f802fSSepherosa Ziehau 	int i, error, pktenq;
2764fa8e46eSSepherosa Ziehau 
277391741ecSSepherosa Ziehau 	if (pktg->pktg_flags & (PKTG_F_RUNNING | PKTG_F_CONFIG))
2784fa8e46eSSepherosa Ziehau 		return EBUSY;
2794fa8e46eSSepherosa Ziehau 
280391741ecSSepherosa Ziehau 	if (conf->pc_datalen <= 0 ||
281391741ecSSepherosa Ziehau 	    conf->pc_datalen > ETHERMTU - sizeof(struct udpiphdr))
2824fa8e46eSSepherosa Ziehau 		return EINVAL;
2834fa8e46eSSepherosa Ziehau 	if (conf->pc_duration <= 0)
2844fa8e46eSSepherosa Ziehau 		return EINVAL;
2854fa8e46eSSepherosa Ziehau 
2864fa8e46eSSepherosa Ziehau 	sin = &conf->pc_src;
2874fa8e46eSSepherosa Ziehau 	if (sin->sin_family != AF_INET)
2884fa8e46eSSepherosa Ziehau 		return EPROTONOSUPPORT;
2894fa8e46eSSepherosa Ziehau 	if (sin->sin_port == 0)
2904fa8e46eSSepherosa Ziehau 		return EINVAL;
2914fa8e46eSSepherosa Ziehau 
292391741ecSSepherosa Ziehau 	if (conf->pc_ndst <= 0)
2934fa8e46eSSepherosa Ziehau 		return EINVAL;
294391741ecSSepherosa Ziehau 	dst_size = conf->pc_ndst * sizeof(struct sockaddr_in);
2954fa8e46eSSepherosa Ziehau 
296391741ecSSepherosa Ziehau 	dst = kmalloc(dst_size, M_PKTGEN, M_WAITOK | M_NULLOK);
297391741ecSSepherosa Ziehau 	if (dst == NULL)
298391741ecSSepherosa Ziehau 		return ENOMEM;
299391741ecSSepherosa Ziehau 
300391741ecSSepherosa Ziehau 	error = copyin(conf->pc_dst, dst, dst_size);
301391741ecSSepherosa Ziehau 	if (error)
302391741ecSSepherosa Ziehau 		goto failed;
303391741ecSSepherosa Ziehau 
304391741ecSSepherosa Ziehau 	for (i = 0; i < conf->pc_ndst; ++i) {
305391741ecSSepherosa Ziehau 		sin = &dst[i];
306391741ecSSepherosa Ziehau 		if (sin->sin_family != AF_INET) {
307391741ecSSepherosa Ziehau 			error = EPROTONOSUPPORT;
308391741ecSSepherosa Ziehau 			goto failed;
309391741ecSSepherosa Ziehau 		}
310391741ecSSepherosa Ziehau 		if (sin->sin_port == 0) {
311391741ecSSepherosa Ziehau 			error = EINVAL;
312391741ecSSepherosa Ziehau 			goto failed;
313391741ecSSepherosa Ziehau 		}
314391741ecSSepherosa Ziehau 	}
315391741ecSSepherosa Ziehau 
31673d83e2bSSepherosa Ziehau 	/*
31773d83e2bSSepherosa Ziehau 	 * XXX NOT MPSAFE.
31873d83e2bSSepherosa Ziehau 	 * Make sure that pc_ifname is not gone.
31973d83e2bSSepherosa Ziehau 	 */
32073d83e2bSSepherosa Ziehau 	ifnet_lock();
321391741ecSSepherosa Ziehau 	ifp = ifunit(conf->pc_ifname);
32273d83e2bSSepherosa Ziehau 	ifnet_unlock();
323391741ecSSepherosa Ziehau 	if (ifp == NULL) {
324391741ecSSepherosa Ziehau 		error = ENXIO;
325391741ecSSepherosa Ziehau 		goto failed;
326391741ecSSepherosa Ziehau 	}
327391741ecSSepherosa Ziehau 
328793f802fSSepherosa Ziehau 	pktenq = conf->pc_pktenq;
3292fb36fabSSepherosa Ziehau 	if (pktenq < 0 || pktenq > ifp->if_snd.altq_maxlen) {
330793f802fSSepherosa Ziehau 		error = ENOBUFS;
331793f802fSSepherosa Ziehau 		goto failed;
332793f802fSSepherosa Ziehau 	} else if (pktenq == 0) {
3332fb36fabSSepherosa Ziehau 		pktenq = (ifp->if_snd.altq_maxlen * 3) / 4;
334793f802fSSepherosa Ziehau 	}
335793f802fSSepherosa Ziehau 
336391741ecSSepherosa Ziehau 	sa = &conf->pc_dst_lladdr;
337391741ecSSepherosa Ziehau 	if (sa->sa_family != AF_LINK) {
338391741ecSSepherosa Ziehau 		error = EPROTONOSUPPORT;
339391741ecSSepherosa Ziehau 		goto failed;
340391741ecSSepherosa Ziehau 	}
341391741ecSSepherosa Ziehau 	if (sa->sa_len != ETHER_ADDR_LEN) {
342391741ecSSepherosa Ziehau 		error = EPROTONOSUPPORT;
343391741ecSSepherosa Ziehau 		goto failed;
344391741ecSSepherosa Ziehau 	}
345391741ecSSepherosa Ziehau 	if (ETHER_IS_MULTICAST(sa->sa_data) ||
346391741ecSSepherosa Ziehau 	    bcmp(sa->sa_data, ifp->if_broadcastaddr, ifp->if_addrlen) == 0) {
347391741ecSSepherosa Ziehau 		error = EADDRNOTAVAIL;
348391741ecSSepherosa Ziehau 		goto failed;
349391741ecSSepherosa Ziehau 	}
350391741ecSSepherosa Ziehau 
351391741ecSSepherosa Ziehau 	/*
352391741ecSSepherosa Ziehau 	 * Accept the config
353391741ecSSepherosa Ziehau 	 */
3544fa8e46eSSepherosa Ziehau 	pktg->pktg_flags |= PKTG_F_CONFIG;
3554fa8e46eSSepherosa Ziehau 
356eec66bd4SSepherosa Ziehau 	if (conf->pc_flags & PKTGEN_FLAG_SWITCH_SRCDST)
357eec66bd4SSepherosa Ziehau 		pktg->pktg_flags |= PKTG_F_SWITCH_SRCDST;
3584fa8e46eSSepherosa Ziehau 	pktg->pktg_duration = conf->pc_duration;
3594fa8e46eSSepherosa Ziehau 	pktg->pktg_datalen = conf->pc_datalen;
360793f802fSSepherosa Ziehau 	pktg->pktg_pktenq = pktenq;
361391741ecSSepherosa Ziehau 	pktg->pktg_ifp = ifp;
362391741ecSSepherosa Ziehau 	pktg->pktg_src = conf->pc_src;
363391741ecSSepherosa Ziehau 	pktg->pktg_ndst = conf->pc_ndst;
364391741ecSSepherosa Ziehau 	KKASSERT(pktg->pktg_dst == NULL);
365391741ecSSepherosa Ziehau 	pktg->pktg_dst = dst;
3664fa8e46eSSepherosa Ziehau 	bcopy(sa->sa_data, pktg->pktg_dst_lladdr, ETHER_ADDR_LEN);
367c95ebcd6SSepherosa Ziehau 
3684fa8e46eSSepherosa Ziehau 	return 0;
369391741ecSSepherosa Ziehau 
370391741ecSSepherosa Ziehau failed:
371391741ecSSepherosa Ziehau 	if (dst != NULL)
372391741ecSSepherosa Ziehau 		kfree(dst, M_PKTGEN);
373391741ecSSepherosa Ziehau 	return error;
3744fa8e46eSSepherosa Ziehau }
3754fa8e46eSSepherosa Ziehau 
376b0cd2b4bSSepherosa Ziehau static void
pktgen_start_ifsq(struct pktgen * pktg,struct ifaltq_subque * ifsq)377b0cd2b4bSSepherosa Ziehau pktgen_start_ifsq(struct pktgen *pktg, struct ifaltq_subque *ifsq)
3784fa8e46eSSepherosa Ziehau {
379b0cd2b4bSSepherosa Ziehau 	struct netmsg_pktgen *np;
380391741ecSSepherosa Ziehau 
381b0cd2b4bSSepherosa Ziehau 	np = kmalloc(sizeof(*np), M_LWKTMSG, M_WAITOK);
382b0cd2b4bSSepherosa Ziehau 	netmsg_init(&np->np_base, NULL, &netisr_afree_rport, 0,
383b0cd2b4bSSepherosa Ziehau 	    pktgen_start_ifsq_handler);
384b0cd2b4bSSepherosa Ziehau 	np->np_pktg = pktg;
385b0cd2b4bSSepherosa Ziehau 	np->np_ifsq = ifsq;
386b0cd2b4bSSepherosa Ziehau 
387ec7f7fc8SSepherosa Ziehau 	lwkt_sendmsg(netisr_cpuport(ifsq_get_cpuid(ifsq)), &np->np_base.lmsg);
388b0cd2b4bSSepherosa Ziehau }
389b0cd2b4bSSepherosa Ziehau 
390b0cd2b4bSSepherosa Ziehau static int
pktgen_start(struct pktgen * pktg,int mq)391b0cd2b4bSSepherosa Ziehau pktgen_start(struct pktgen *pktg, int mq)
392b0cd2b4bSSepherosa Ziehau {
393b0cd2b4bSSepherosa Ziehau 	struct ifaltq *ifq;
394391741ecSSepherosa Ziehau 
3954fa8e46eSSepherosa Ziehau 	if ((pktg->pktg_flags & PKTG_F_CONFIG) == 0)
3964fa8e46eSSepherosa Ziehau 		return EINVAL;
3974fa8e46eSSepherosa Ziehau 	if (pktg->pktg_flags & PKTG_F_RUNNING)
3984fa8e46eSSepherosa Ziehau 		return EBUSY;
3994fa8e46eSSepherosa Ziehau 	pktg->pktg_flags |= PKTG_F_RUNNING;
4004fa8e46eSSepherosa Ziehau 
401b0cd2b4bSSepherosa Ziehau 	ifq = &pktg->pktg_ifp->if_snd;
402b0cd2b4bSSepherosa Ziehau 	if (!mq) {
403b0cd2b4bSSepherosa Ziehau 		pktgen_ref(pktg);
404b0cd2b4bSSepherosa Ziehau 		pktgen_start_ifsq(pktg, ifq_get_subq_default(ifq));
405b0cd2b4bSSepherosa Ziehau 	} else {
406b0cd2b4bSSepherosa Ziehau 		int i;
407391741ecSSepherosa Ziehau 
408b0cd2b4bSSepherosa Ziehau 		for (i = 0; i < ifq->altq_subq_cnt; ++i)
409b0cd2b4bSSepherosa Ziehau 			pktgen_ref(pktg);
410b0cd2b4bSSepherosa Ziehau 		for (i = 0; i < ifq->altq_subq_cnt; ++i)
411b0cd2b4bSSepherosa Ziehau 			pktgen_start_ifsq(pktg, ifq_get_subq(ifq, i));
412b0cd2b4bSSepherosa Ziehau 	}
413b0cd2b4bSSepherosa Ziehau 	return 0;
414b0cd2b4bSSepherosa Ziehau }
415b0cd2b4bSSepherosa Ziehau 
416b0cd2b4bSSepherosa Ziehau static void
pktgen_start_ifsq_handler(netmsg_t nmsg)417b0cd2b4bSSepherosa Ziehau pktgen_start_ifsq_handler(netmsg_t nmsg)
418b0cd2b4bSSepherosa Ziehau {
419b0cd2b4bSSepherosa Ziehau 	struct netmsg_pktgen *np = (struct netmsg_pktgen *)nmsg;
420b0cd2b4bSSepherosa Ziehau 	struct pktgen *pktg = np->np_pktg;
421b0cd2b4bSSepherosa Ziehau 	struct ifaltq_subque *ifsq = np->np_ifsq;
422b0cd2b4bSSepherosa Ziehau 
423b0cd2b4bSSepherosa Ziehau 	struct mbuf *m, *head = NULL, **next;
424b0cd2b4bSSepherosa Ziehau 	struct ifnet *ifp;
425b0cd2b4bSSepherosa Ziehau 	struct pktgen_pcpu *p;
426b0cd2b4bSSepherosa Ziehau 	int cpuid, i, alloc_cnt, keep_cnt;
427b0cd2b4bSSepherosa Ziehau 
428b0cd2b4bSSepherosa Ziehau 	u_short ulen, psum;
429b0cd2b4bSSepherosa Ziehau 	int len, ip_len;
430b0cd2b4bSSepherosa Ziehau 
431b0cd2b4bSSepherosa Ziehau 	/* Reply ASAP */
432b0cd2b4bSSepherosa Ziehau 	lwkt_replymsg(&np->np_base.lmsg, 0);
433b0cd2b4bSSepherosa Ziehau 
434b0cd2b4bSSepherosa Ziehau 	ifp = pktg->pktg_ifp;
435b0cd2b4bSSepherosa Ziehau 
4362fb36fabSSepherosa Ziehau 	cpuid = ifsq_get_cpuid(ifsq);
437b0cd2b4bSSepherosa Ziehau 	KKASSERT(cpuid == mycpuid);
438391741ecSSepherosa Ziehau 
4391bbaa2adSSepherosa Ziehau 	p = &pktg->pktg_pcpu[cpuid];
4401bbaa2adSSepherosa Ziehau 
441793f802fSSepherosa Ziehau 	keep_cnt = pktg->pktg_pktenq;
442793f802fSSepherosa Ziehau 	alloc_cnt = keep_cnt * 2;
443391741ecSSepherosa Ziehau 
444391741ecSSepherosa Ziehau 	/*
445391741ecSSepherosa Ziehau 	 * Prefault enough mbuf into mbuf objcache
446391741ecSSepherosa Ziehau 	 */
447391741ecSSepherosa Ziehau 	next = &head;
448391741ecSSepherosa Ziehau 	for (i = 0; i < alloc_cnt; ++i) {
449b5523eacSSascha Wildner 		MGETHDR(m, M_WAITOK, MT_DATA);
450391741ecSSepherosa Ziehau 		*next = m;
451391741ecSSepherosa Ziehau 		next = &m->m_nextpkt;
452391741ecSSepherosa Ziehau 	}
453391741ecSSepherosa Ziehau 
454391741ecSSepherosa Ziehau 	for (i = 0; i < alloc_cnt - keep_cnt; ++i) {
455391741ecSSepherosa Ziehau 		m = head;
456391741ecSSepherosa Ziehau 		head = m->m_nextpkt;
457391741ecSSepherosa Ziehau 		m->m_nextpkt = NULL;
458391741ecSSepherosa Ziehau 		m_freem(m);
459391741ecSSepherosa Ziehau 	}
460391741ecSSepherosa Ziehau 	KKASSERT(head != NULL);
461391741ecSSepherosa Ziehau 
462391741ecSSepherosa Ziehau 	/*
463391741ecSSepherosa Ziehau 	 * Setup the packets' data
464391741ecSSepherosa Ziehau 	 */
465391741ecSSepherosa Ziehau 	ip_len = pktg->pktg_datalen + sizeof(struct udpiphdr);
466391741ecSSepherosa Ziehau 	len = ip_len + ETHER_HDR_LEN;
467391741ecSSepherosa Ziehau 
468391741ecSSepherosa Ziehau 	psum = htons((u_short)pktg->pktg_datalen + sizeof(struct udphdr) +
469391741ecSSepherosa Ziehau 	    IPPROTO_UDP);
470391741ecSSepherosa Ziehau 	ulen = htons(pktg->pktg_datalen + sizeof(struct udphdr));
471391741ecSSepherosa Ziehau 
472391741ecSSepherosa Ziehau 	m = head;
473391741ecSSepherosa Ziehau 	i = 0;
474391741ecSSepherosa Ziehau 	while (m != NULL) {
475391741ecSSepherosa Ziehau 		struct mbuf *nextm;
476391741ecSSepherosa Ziehau 		const struct sockaddr_in *dst;
477391741ecSSepherosa Ziehau 		struct pktgen_buf *pb;
478391741ecSSepherosa Ziehau 		struct ip *ip;
479391741ecSSepherosa Ziehau 		struct udpiphdr *ui;
480391741ecSSepherosa Ziehau 		struct ether_header *eh;
481391741ecSSepherosa Ziehau 
482c6830078SSepherosa Ziehau 		pktgen_ref(pktg);
483391741ecSSepherosa Ziehau 
484391741ecSSepherosa Ziehau 		pb = kmalloc(sizeof(*pb), M_PKTGEN, M_WAITOK | M_ZERO);
485391741ecSSepherosa Ziehau 		pb->pb_ifp = ifp;
4862fb36fabSSepherosa Ziehau 		pb->pb_ifsq = ifsq;
487391741ecSSepherosa Ziehau 		pb->pb_inuse = 1;
488391741ecSSepherosa Ziehau 		pb->pb_buf = kmalloc(PKTGEN_BUFSZ, M_PKTGEN, M_WAITOK);
489391741ecSSepherosa Ziehau 		pb->pb_len = len;
490391741ecSSepherosa Ziehau 		pb->pb_cpuid = cpuid;
491391741ecSSepherosa Ziehau 		pb->pb_pktg = pktg;
492391741ecSSepherosa Ziehau 		netmsg_init(&pb->pb_nmsg, NULL, &netisr_adone_rport, 0,
493391741ecSSepherosa Ziehau 		    pktgen_buf_send);
4941bbaa2adSSepherosa Ziehau 		LIST_INSERT_HEAD(&p->pktg_buflist, pb, pb_link);
495391741ecSSepherosa Ziehau 
496391741ecSSepherosa Ziehau 		dst = &pktg->pktg_dst[i % pktg->pktg_ndst];
497391741ecSSepherosa Ziehau 		++i;
498391741ecSSepherosa Ziehau 
499391741ecSSepherosa Ziehau 		m->m_ext.ext_arg = pb;
500391741ecSSepherosa Ziehau 		m->m_ext.ext_buf = pb->pb_buf;
501391741ecSSepherosa Ziehau 		m->m_ext.ext_free = pktgen_buf_free;
502391741ecSSepherosa Ziehau 		m->m_ext.ext_ref = pktgen_buf_ref;
503391741ecSSepherosa Ziehau 		m->m_ext.ext_size = PKTGEN_BUFSZ;
504391741ecSSepherosa Ziehau 
505391741ecSSepherosa Ziehau 		m->m_data = m->m_ext.ext_buf;
506391741ecSSepherosa Ziehau 		m->m_flags |= M_EXT;
507391741ecSSepherosa Ziehau 		m->m_len = m->m_pkthdr.len = len;
508391741ecSSepherosa Ziehau 
509391741ecSSepherosa Ziehau 		m->m_data += ETHER_HDR_LEN;
510391741ecSSepherosa Ziehau 		m->m_len -= ETHER_HDR_LEN;
511391741ecSSepherosa Ziehau 		m->m_pkthdr.len -= ETHER_HDR_LEN;
512391741ecSSepherosa Ziehau 
513391741ecSSepherosa Ziehau 		ui = mtod(m, struct udpiphdr *);
514391741ecSSepherosa Ziehau 		ui->ui_pr = IPPROTO_UDP;
515eec66bd4SSepherosa Ziehau 		if (pktg->pktg_flags & PKTG_F_SWITCH_SRCDST) {
516eec66bd4SSepherosa Ziehau 			ui->ui_src.s_addr = dst->sin_addr.s_addr;
517eec66bd4SSepherosa Ziehau 			ui->ui_dst.s_addr = pktg->pktg_src.sin_addr.s_addr;
518eec66bd4SSepherosa Ziehau 			ui->ui_sport = dst->sin_port;
519eec66bd4SSepherosa Ziehau 			ui->ui_dport = pktg->pktg_src.sin_port;
520eec66bd4SSepherosa Ziehau 		} else {
521391741ecSSepherosa Ziehau 			ui->ui_src.s_addr = pktg->pktg_src.sin_addr.s_addr;
522391741ecSSepherosa Ziehau 			ui->ui_dst.s_addr = dst->sin_addr.s_addr;
523391741ecSSepherosa Ziehau 			ui->ui_sport = pktg->pktg_src.sin_port;
524391741ecSSepherosa Ziehau 			ui->ui_dport = dst->sin_port;
525eec66bd4SSepherosa Ziehau 		}
526391741ecSSepherosa Ziehau 		ui->ui_ulen = ulen;
527391741ecSSepherosa Ziehau 		ui->ui_sum = in_pseudo(ui->ui_src.s_addr, ui->ui_dst.s_addr,
528391741ecSSepherosa Ziehau 		    psum);
52964c94a5fSSepherosa Ziehau 		m->m_pkthdr.csum_data = offsetof(struct udphdr, uh_sum);
530391741ecSSepherosa Ziehau 
531391741ecSSepherosa Ziehau 		ip = (struct ip *)ui;
532391741ecSSepherosa Ziehau 		ip->ip_len = ip_len;
533391741ecSSepherosa Ziehau 		ip->ip_ttl = 64;	/* XXX */
534391741ecSSepherosa Ziehau 		ip->ip_tos = 0;		/* XXX */
535391741ecSSepherosa Ziehau 		ip->ip_vhl = IP_VHL_BORING;
536391741ecSSepherosa Ziehau 		ip->ip_off = 0;
5372640b9e5SSepherosa Ziehau 		ip->ip_sum = 0;
538391741ecSSepherosa Ziehau 		ip->ip_id = ip_newid();
539391741ecSSepherosa Ziehau 
540391741ecSSepherosa Ziehau 		in_delayed_cksum(m);
541391741ecSSepherosa Ziehau 
542391741ecSSepherosa Ziehau 		ip->ip_len = htons(ip->ip_len);
543391741ecSSepherosa Ziehau 		ip->ip_sum = in_cksum_hdr(ip);
544391741ecSSepherosa Ziehau 
545391741ecSSepherosa Ziehau 		m->m_data -= ETHER_HDR_LEN;
546391741ecSSepherosa Ziehau 		m->m_len += ETHER_HDR_LEN;
547391741ecSSepherosa Ziehau 		m->m_pkthdr.len += ETHER_HDR_LEN;
548391741ecSSepherosa Ziehau 
549391741ecSSepherosa Ziehau 		eh = mtod(m, struct ether_header *);
550391741ecSSepherosa Ziehau 		bcopy(pktg->pktg_dst_lladdr, eh->ether_dhost, ETHER_ADDR_LEN);
551391741ecSSepherosa Ziehau 		bcopy(IF_LLADDR(ifp), eh->ether_shost, ETHER_ADDR_LEN);
552391741ecSSepherosa Ziehau 		eh->ether_type = htons(ETHERTYPE_IP);
553391741ecSSepherosa Ziehau 
554391741ecSSepherosa Ziehau 		nextm = m->m_nextpkt;
555391741ecSSepherosa Ziehau 		m->m_nextpkt = NULL;
556391741ecSSepherosa Ziehau 
557391741ecSSepherosa Ziehau 		ifq_dispatch(ifp, m, NULL);
558391741ecSSepherosa Ziehau 
559391741ecSSepherosa Ziehau 		m = nextm;
560391741ecSSepherosa Ziehau 	}
561391741ecSSepherosa Ziehau 
5621bbaa2adSSepherosa Ziehau 	callout_reset(&p->pktg_stop, pktg->pktg_duration * hz,
5631bbaa2adSSepherosa Ziehau 	    pktgen_pcpu_stop_cb, p);
564391741ecSSepherosa Ziehau 
565b0cd2b4bSSepherosa Ziehau 	pktgen_free(pktg);
5664fa8e46eSSepherosa Ziehau }
5674fa8e46eSSepherosa Ziehau 
5684fa8e46eSSepherosa Ziehau static void
pktgen_mbuf(struct pktgen_buf * pb,struct mbuf * m)569391741ecSSepherosa Ziehau pktgen_mbuf(struct pktgen_buf *pb, struct mbuf *m)
570391741ecSSepherosa Ziehau {
571391741ecSSepherosa Ziehau 	m->m_ext.ext_arg = pb;
572391741ecSSepherosa Ziehau 	m->m_ext.ext_buf = pb->pb_buf;
573391741ecSSepherosa Ziehau 	m->m_ext.ext_free = pktgen_buf_free;
574391741ecSSepherosa Ziehau 	m->m_ext.ext_ref = pktgen_buf_ref;
575391741ecSSepherosa Ziehau 	m->m_ext.ext_size = PKTGEN_BUFSZ;
576391741ecSSepherosa Ziehau 
577391741ecSSepherosa Ziehau 	m->m_data = m->m_ext.ext_buf;
578391741ecSSepherosa Ziehau 	m->m_flags |= M_EXT;
579391741ecSSepherosa Ziehau 	m->m_len = m->m_pkthdr.len = pb->pb_len;
580391741ecSSepherosa Ziehau }
581391741ecSSepherosa Ziehau 
582391741ecSSepherosa Ziehau static void
pktgen_buf_send(netmsg_t msg)583391741ecSSepherosa Ziehau pktgen_buf_send(netmsg_t msg)
584391741ecSSepherosa Ziehau {
585391741ecSSepherosa Ziehau 	struct pktgen_buf *pb = (struct pktgen_buf *)msg;
586391741ecSSepherosa Ziehau 	struct mbuf *m;
587391741ecSSepherosa Ziehau 
588ec7f7fc8SSepherosa Ziehau 	KKASSERT(&curthread->td_msgport == netisr_cpuport(pb->pb_cpuid));
589391741ecSSepherosa Ziehau 
590391741ecSSepherosa Ziehau 	crit_enter();
591391741ecSSepherosa Ziehau 	lwkt_replymsg(&pb->pb_nmsg.lmsg, 0);
592391741ecSSepherosa Ziehau 	crit_exit();
593391741ecSSepherosa Ziehau 
594b5523eacSSascha Wildner 	MGETHDR(m, M_WAITOK, MT_DATA);
595391741ecSSepherosa Ziehau 	pktgen_mbuf(pb, m);
596391741ecSSepherosa Ziehau 	ifq_dispatch(pb->pb_ifp, m, NULL);
597391741ecSSepherosa Ziehau }
598391741ecSSepherosa Ziehau 
599391741ecSSepherosa Ziehau static void
pktgen_buf_free(void * arg)600391741ecSSepherosa Ziehau pktgen_buf_free(void *arg)
601391741ecSSepherosa Ziehau {
602391741ecSSepherosa Ziehau 	struct pktgen_buf *pb = arg;
603391741ecSSepherosa Ziehau 	struct mbuf *m;
604391741ecSSepherosa Ziehau 
605391741ecSSepherosa Ziehau 	KKASSERT(pb->pb_inuse > 0);
606391741ecSSepherosa Ziehau 	if (pb->pb_done) {
607391741ecSSepherosa Ziehau 		if (atomic_fetchadd_int(&pb->pb_inuse, -1) == 1) {
608391741ecSSepherosa Ziehau 			struct pktgen *pktg;
609391741ecSSepherosa Ziehau 
610391741ecSSepherosa Ziehau 			pktg = pb->pb_pktg;
6114c9906cbSSepherosa Ziehau 			crit_enter();
612391741ecSSepherosa Ziehau 			LIST_REMOVE(pb, pb_link);
6134c9906cbSSepherosa Ziehau 			crit_exit();
614391741ecSSepherosa Ziehau 			kfree(pb->pb_buf, M_PKTGEN);
615391741ecSSepherosa Ziehau 			kfree(pb, M_PKTGEN);
616391741ecSSepherosa Ziehau 
617391741ecSSepherosa Ziehau 			pktgen_free(pktg);
618391741ecSSepherosa Ziehau 		}
619391741ecSSepherosa Ziehau 		return;
620391741ecSSepherosa Ziehau 	}
621391741ecSSepherosa Ziehau 
622ec7f7fc8SSepherosa Ziehau 	if (&curthread->td_msgport != netisr_cpuport(pb->pb_cpuid)) {
623391741ecSSepherosa Ziehau 		KKASSERT(pb->pb_cpuid == mycpuid);
624391741ecSSepherosa Ziehau 		crit_enter();
625391741ecSSepherosa Ziehau 		KKASSERT(pb->pb_nmsg.lmsg.ms_flags & MSGF_DONE);
626ec7f7fc8SSepherosa Ziehau 		lwkt_sendmsg(netisr_cpuport(pb->pb_cpuid), &pb->pb_nmsg.lmsg);
627391741ecSSepherosa Ziehau 		crit_exit();
628391741ecSSepherosa Ziehau 		return;
629391741ecSSepherosa Ziehau 	}
630391741ecSSepherosa Ziehau 
631b5523eacSSascha Wildner 	MGETHDR(m, M_WAITOK, MT_DATA);
632391741ecSSepherosa Ziehau 	pktgen_mbuf(pb, m);
6332fb36fabSSepherosa Ziehau 	ifsq_enqueue(pb->pb_ifsq, m, NULL);
634391741ecSSepherosa Ziehau }
635391741ecSSepherosa Ziehau 
636391741ecSSepherosa Ziehau static void
pktgen_buf_ref(void * arg)637391741ecSSepherosa Ziehau pktgen_buf_ref(void *arg)
638391741ecSSepherosa Ziehau {
639391741ecSSepherosa Ziehau 	struct pktgen_buf *pb = arg;
640391741ecSSepherosa Ziehau 
641391741ecSSepherosa Ziehau 	panic("%s should never be called\n", __func__);
642391741ecSSepherosa Ziehau 
643391741ecSSepherosa Ziehau 	KKASSERT(pb->pb_inuse > 0);
644391741ecSSepherosa Ziehau 	atomic_add_int(&pb->pb_inuse, 1);
645391741ecSSepherosa Ziehau }
646391741ecSSepherosa Ziehau 
647391741ecSSepherosa Ziehau static void
pktgen_free(struct pktgen * pktg)648391741ecSSepherosa Ziehau pktgen_free(struct pktgen *pktg)
649391741ecSSepherosa Ziehau {
650391741ecSSepherosa Ziehau 	KKASSERT(pktg->pktg_refcnt > 0);
6514c9906cbSSepherosa Ziehau 	if (atomic_fetchadd_int(&pktg->pktg_refcnt, -1) == 1) {
6521bbaa2adSSepherosa Ziehau 		int i;
6531bbaa2adSSepherosa Ziehau 
654391741ecSSepherosa Ziehau 		if (pktg->pktg_dst != NULL)
655391741ecSSepherosa Ziehau 			kfree(pktg->pktg_dst, M_PKTGEN);
6561bbaa2adSSepherosa Ziehau 
6571bbaa2adSSepherosa Ziehau 		for (i = 0; i < ncpus; ++i)
6581bbaa2adSSepherosa Ziehau 			KKASSERT(LIST_EMPTY(&pktg->pktg_pcpu[i].pktg_buflist));
659391741ecSSepherosa Ziehau 		kfree(pktg, M_PKTGEN);
660391741ecSSepherosa Ziehau 	}
661391741ecSSepherosa Ziehau 
662391741ecSSepherosa Ziehau 	KKASSERT(pktgen_refcnt > 0);
6634c9906cbSSepherosa Ziehau 	atomic_subtract_int(&pktgen_refcnt, 1);
664391741ecSSepherosa Ziehau }
665391741ecSSepherosa Ziehau 
666391741ecSSepherosa Ziehau static void
pktgen_pcpu_stop_cb(void * arg)6671bbaa2adSSepherosa Ziehau pktgen_pcpu_stop_cb(void *arg)
6684fa8e46eSSepherosa Ziehau {
6691bbaa2adSSepherosa Ziehau 	struct pktgen_pcpu *p = arg;
670391741ecSSepherosa Ziehau 	struct pktgen_buf *pb;
6714fa8e46eSSepherosa Ziehau 
6724c9906cbSSepherosa Ziehau 	crit_enter();
6731bbaa2adSSepherosa Ziehau 	LIST_FOREACH(pb, &p->pktg_buflist, pb_link)
674391741ecSSepherosa Ziehau 		pb->pb_done = 1;
6754c9906cbSSepherosa Ziehau 	crit_exit();
6764fa8e46eSSepherosa Ziehau }
677c6830078SSepherosa Ziehau 
678c6830078SSepherosa Ziehau static void
pktgen_ref(struct pktgen * pktg)679c6830078SSepherosa Ziehau pktgen_ref(struct pktgen *pktg)
680c6830078SSepherosa Ziehau {
681c6830078SSepherosa Ziehau 	atomic_add_int(&pktg->pktg_refcnt, 1);
682c6830078SSepherosa Ziehau 	atomic_add_int(&pktgen_refcnt, 1);
683c6830078SSepherosa Ziehau }
684