xref: /netbsd-src/usr.bin/shmif_pcapin/shmif_pcapin.c (revision 32d1c65c71fbdb65a012e8392a62a757dd6853e9)
1 /*	$NetBSD: shmif_pcapin.c,v 1.1 2024/09/02 05:14:45 ozaki-r Exp $	*/
2 
3 /*-
4  * Copyright (c) 2017-2018 Internet Initiative Japan Inc.
5  * Copyright (c) 2010 Antti Kantee.
6  * All Rights Reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in the
15  *    documentation and/or other materials provided with the distribution.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
18  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
19  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
20  * DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
23  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  */
29 
30 #include <rump/rumpuser_port.h>
31 
32 #ifndef lint
33 __RCSID("$NetBSD: shmif_pcapin.c,v 1.1 2024/09/02 05:14:45 ozaki-r Exp $");
34 #endif /* !lint */
35 
36 #include <stddef.h>
37 #include <sys/types.h>
38 #include <sys/mman.h>
39 #include <sys/stat.h>
40 #include <sys/atomic.h>
41 #include <sys/bswap.h>
42 
43 #include <assert.h>
44 #include <err.h>
45 #include <fcntl.h>
46 #include <inttypes.h>
47 #include <pcap.h>
48 #include <stdbool.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 #include <unistd.h>
53 
54 #include "shmifvar.h"
55 
56 __dead static void
57 usage(void)
58 {
59 
60 #ifndef HAVE_GETPROGNAME
61 #define getprogname() "shmif_pcapin"
62 #endif
63 
64 	fprintf(stderr, "usage: %s pcap-file-path bus-path\n", getprogname());
65 	exit(1);
66 }
67 
68 /*
69  * The BUFSIZE come from shmif_dumpbus.c because there're not any experiences to
70  * make a decision about best size.
71  */
72 #define BUFSIZE 64*1024
73 
74 /*
75  * dowakeup, shmif_lockbus and shmif_unlockbus copy from
76  * sys/rump/net/lib/libshimif/if_shmem.c. So if you have to understood locking
77  * mechanism, you also see that.
78  */
79 static int
80 dowakeup(int memfd)
81 {
82 	struct iovec iov;
83 	uint32_t ver = SHMIF_VERSION;
84 
85 	iov.iov_base = &ver;
86 	iov.iov_len = sizeof(ver);
87 
88 	if (lseek(memfd, IFMEM_WAKEUP, SEEK_SET) == IFMEM_WAKEUP)
89 		return writev(memfd, &iov, 1);
90 	else
91 		return -1;
92 }
93 
94 /*
95  * This locking needs work and will misbehave severely if:
96  * 1) the backing memory has to be paged in
97  * 2) some lockholder exits while holding the lock
98  */
99 static void
100 shmif_lockbus(struct shmif_mem *busmem)
101 {
102 	int i = 0;
103 
104 	while (__predict_false(atomic_cas_32(&busmem->shm_lock,
105 	    LOCK_UNLOCKED, LOCK_LOCKED) == LOCK_LOCKED)) {
106 		if (__predict_false(++i > LOCK_COOLDOWN)) {
107 			usleep(1000);
108 			i = 0;
109 		}
110 		continue;
111 	}
112 	membar_enter();
113 }
114 
115 static void
116 shmif_unlockbus(struct shmif_mem *busmem)
117 {
118 	unsigned int old __diagused;
119 
120 	membar_exit();
121 	old = atomic_swap_32(&busmem->shm_lock, LOCK_UNLOCKED);
122 	assert(old == LOCK_LOCKED);
123 }
124 
125 
126 int
127 main(int argc, char *argv[])
128 {
129 	struct stat sb;
130 	void *busmem;
131 	struct shmif_mem *bmem;
132 	int fd;
133 	const u_char *pkt;
134 	char *buf;
135 	char pcap_errbuf[PCAP_ERRBUF_SIZE];
136 	pcap_t *pcap;
137 	struct pcap_pkthdr pcaphdr;
138 
139 	argc -= optind;
140 	argv += optind;
141 
142 	if (argc != 2)
143 		usage();
144 
145 	buf = malloc(BUFSIZE);
146 	if (buf == NULL)
147 		err(EXIT_FAILURE, "malloc");
148 
149 	fd = open(argv[1], O_RDWR);
150 	if (fd == -1)
151 		err(EXIT_FAILURE, "open bus");
152 
153 	if (fstat(fd, &sb) == -1)
154 		err(EXIT_FAILURE, "stat");
155 
156 	busmem = mmap(NULL, sb.st_size, PROT_WRITE|PROT_READ,
157 	    MAP_FILE|MAP_SHARED, fd, 0);
158 	if (busmem == MAP_FAILED)
159 		err(EXIT_FAILURE, "mmap");
160 	bmem = busmem;
161 
162 	if (bmem->shm_magic != SHMIF_MAGIC)
163 		errx(EXIT_FAILURE, "%s not a shmif bus", argv[1]);
164 
165 	/*
166 	 * if bmem->shm_version is 0, it indicates to not write any packets
167 	 * by anyone.
168 	 */
169 	if (bmem->shm_version != SHMIF_VERSION && bmem->shm_version != 0)
170 		errx(EXIT_FAILURE, "bus version %d, program %d",
171 		    bmem->shm_version, SHMIF_VERSION);
172 
173 	fprintf(stdout, "bus version %d, lock: %d, generation: %" PRIu64
174 	    ", firstoff: 0x%04x, lastoff: 0x%04x\n", bmem->shm_version,
175 	    bmem->shm_lock, bmem->shm_gen, bmem->shm_first, bmem->shm_last);
176 
177 	pcap = pcap_open_offline(argv[0], pcap_errbuf);
178 	if (pcap == NULL)
179 		err(EXIT_FAILURE, "cannot open pcap file: %s", pcap_errbuf);
180 
181 	while ((pkt = pcap_next(pcap, &pcaphdr))) {
182 		struct shmif_pkthdr sp;
183 		uint32_t dataoff;
184 		struct timeval tv;
185 		bool wrap;
186 
187 		gettimeofday(&tv, NULL);
188 		sp.sp_len = pcaphdr.len;
189 		sp.sp_sec = tv.tv_sec;
190 		sp.sp_usec = tv.tv_usec;
191 		memcpy(buf, pkt, pcaphdr.len);
192 
193 		shmif_lockbus(bmem);
194 
195 		bmem->shm_last = shmif_nextpktoff(bmem, bmem->shm_last);
196 		wrap = false;
197 
198 		dataoff = shmif_buswrite(bmem, bmem->shm_last, &sp,
199 		    sizeof(sp), &wrap);
200 		dataoff = shmif_buswrite(bmem, dataoff, buf, pcaphdr.len, &wrap);
201 
202 		if (wrap)
203 			bmem->shm_gen++;
204 
205 		shmif_unlockbus(bmem);
206 	}
207 
208 	if (dowakeup(fd) == -1)
209 		errx(EXIT_FAILURE, "writev for wakeup");
210 
211 	return 0;
212 }
213