shmif_pcapin.c revision 1.1 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