/src/suricata7/src/util-ioctl.c
Line | Count | Source |
1 | | /* Copyright (C) 2010 Open Information Security Foundation |
2 | | * |
3 | | * You can copy, redistribute or modify this Program under the terms of |
4 | | * the GNU General Public License version 2 as published by the Free |
5 | | * Software Foundation. |
6 | | * |
7 | | * This program is distributed in the hope that it will be useful, |
8 | | * but WITHOUT ANY WARRANTY; without even the implied warranty of |
9 | | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the |
10 | | * GNU General Public License for more details. |
11 | | * |
12 | | * You should have received a copy of the GNU General Public License |
13 | | * version 2 along with this program; if not, write to the Free Software |
14 | | * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA |
15 | | * 02110-1301, USA. |
16 | | */ |
17 | | |
18 | | /** |
19 | | * \file |
20 | | * |
21 | | * \author Eric Leblond <eric@regit.org> |
22 | | * \author Victor Julien <victor@inliniac.net> |
23 | | */ |
24 | | |
25 | | #include "suricata-common.h" |
26 | | #include "util-ioctl.h" |
27 | | #include "conf.h" |
28 | | #include "decode.h" |
29 | | #include "decode-sll.h" |
30 | | |
31 | | #ifdef HAVE_SYS_IOCTL_H |
32 | | #include <sys/ioctl.h> |
33 | | #endif |
34 | | |
35 | | #ifdef HAVE_LINUX_ETHTOOL_H |
36 | | #include <linux/types.h> |
37 | | #include <linux/ethtool.h> |
38 | | #ifdef HAVE_LINUX_SOCKIOS_H |
39 | | #include <linux/sockios.h> |
40 | | #else |
41 | | #error "ethtool.h present but sockios.h is missing" |
42 | | #endif /* HAVE_LINUX_SOCKIOS_H */ |
43 | | #endif /* HAVE_LINUX_ETHTOOL_H */ |
44 | | |
45 | | #ifdef HAVE_NET_IF_H |
46 | | #include <net/if.h> |
47 | | #endif |
48 | | |
49 | | #ifdef OS_WIN32 |
50 | | #include "win32-syscall.h" |
51 | | #endif |
52 | | |
53 | | /** |
54 | | * \brief output a majorant of hardware header length |
55 | | * |
56 | | * \param Name of a network interface |
57 | | */ |
58 | | static int GetIfaceMaxHWHeaderLength(const char *dev) |
59 | 0 | { |
60 | 0 | if ((!strcmp("eth", dev)) || (!strcmp("br", dev)) || (!strcmp("bond", dev)) || |
61 | 0 | (!strcmp("wlan", dev)) || (!strcmp("tun", dev)) || (!strcmp("tap", dev)) || |
62 | 0 | (!strcmp("lo", dev))) { |
63 | | /* Add possible VLAN tag or Qing headers */ |
64 | 0 | return 8 + ETHERNET_HEADER_LEN; |
65 | 0 | } |
66 | | |
67 | 0 | if (!strcmp("ppp", dev)) |
68 | 0 | return SLL_HEADER_LEN; |
69 | | /* SLL_HEADER_LEN is the biggest one and |
70 | | add possible VLAN tag and Qing headers */ |
71 | 0 | return 8 + SLL_HEADER_LEN; |
72 | 0 | } |
73 | | |
74 | | |
75 | | /** |
76 | | * \brief output the link MTU |
77 | | * |
78 | | * \param Name of link |
79 | | * \retval -1 in case of error, 0 if MTU can not be found |
80 | | */ |
81 | | int GetIfaceMTU(const char *dev) |
82 | 0 | { |
83 | 0 | #if defined SIOCGIFMTU |
84 | 0 | struct ifreq ifr; |
85 | 0 | int fd; |
86 | |
|
87 | 0 | (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); |
88 | 0 | fd = socket(AF_INET, SOCK_DGRAM, 0); |
89 | 0 | if (fd == -1) { |
90 | 0 | return -1; |
91 | 0 | } |
92 | | |
93 | 0 | if (ioctl(fd, SIOCGIFMTU, (char *)&ifr) < 0) { |
94 | 0 | SCLogWarning("Failure when trying to get MTU via ioctl for '%s': %s (%d)", dev, |
95 | 0 | strerror(errno), errno); |
96 | 0 | close(fd); |
97 | 0 | return -1; |
98 | 0 | } |
99 | 0 | close(fd); |
100 | 0 | SCLogInfo("%s: MTU %d", dev, ifr.ifr_mtu); |
101 | 0 | return ifr.ifr_mtu; |
102 | | #elif defined OS_WIN32 |
103 | | return GetIfaceMTUWin32(dev); |
104 | | #else |
105 | | /* ioctl is not defined, let's pretend returning 0 is ok */ |
106 | | return 0; |
107 | | #endif |
108 | 0 | } |
109 | | |
110 | | /** |
111 | | * \brief output max packet size for a link |
112 | | * |
113 | | * This does a best effort to find the maximum packet size |
114 | | * for the link. In case of uncertainty, it will output a |
115 | | * majorant to be sure avoid the cost of dynamic allocation. |
116 | | * |
117 | | * \param LiveDevice object |
118 | | * \retval 0 in case of error |
119 | | */ |
120 | | int GetIfaceMaxPacketSize(LiveDevice *ld) |
121 | 0 | { |
122 | 0 | if (ld == NULL) |
123 | 0 | return 0; |
124 | | |
125 | 0 | const char *dev = ld->dev; |
126 | 0 | if ((dev == NULL) || strlen(dev) == 0) |
127 | 0 | return 0; |
128 | | |
129 | 0 | int mtu = GetIfaceMTU(dev); |
130 | 0 | switch (mtu) { |
131 | 0 | case 0: |
132 | 0 | case -1: |
133 | 0 | return 0; |
134 | 0 | } |
135 | 0 | ld->mtu = mtu; |
136 | 0 | int ll_header = GetIfaceMaxHWHeaderLength(dev); |
137 | 0 | return ll_header + mtu; |
138 | 0 | } |
139 | | |
140 | | #ifdef SIOCGIFFLAGS |
141 | | /** |
142 | | * \brief Get interface flags. |
143 | | * \param ifname Interface name. |
144 | | * \return Interface flags or -1 on error |
145 | | */ |
146 | | int GetIfaceFlags(const char *ifname) |
147 | 0 | { |
148 | 0 | struct ifreq ifr; |
149 | |
|
150 | 0 | int fd = socket(AF_INET, SOCK_DGRAM, 0); |
151 | 0 | if (fd < 0) { |
152 | 0 | return -1; |
153 | 0 | } |
154 | | |
155 | 0 | memset(&ifr, 0, sizeof(ifr)); |
156 | 0 | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
157 | |
|
158 | 0 | if (ioctl(fd, SIOCGIFFLAGS, &ifr) == -1) { |
159 | 0 | SCLogError("%s: failed to get device flags: %s", ifname, strerror(errno)); |
160 | 0 | close(fd); |
161 | 0 | return -1; |
162 | 0 | } |
163 | | |
164 | 0 | close(fd); |
165 | | #ifdef OS_FREEBSD |
166 | | int flags = (ifr.ifr_flags & 0xffff) | (ifr.ifr_flagshigh << 16); |
167 | | return flags; |
168 | | #else |
169 | 0 | return ifr.ifr_flags; |
170 | 0 | #endif |
171 | 0 | } |
172 | | #endif |
173 | | |
174 | | #ifdef SIOCSIFFLAGS |
175 | | /** |
176 | | * \brief Set interface flags. |
177 | | * \param ifname Interface name. |
178 | | * \param flags Flags to set. |
179 | | * \return Zero on success. |
180 | | */ |
181 | | int SetIfaceFlags(const char *ifname, int flags) |
182 | 0 | { |
183 | 0 | struct ifreq ifr; |
184 | |
|
185 | 0 | int fd = socket(AF_INET, SOCK_DGRAM, 0); |
186 | 0 | if (fd < 0) { |
187 | 0 | return -1; |
188 | 0 | } |
189 | | |
190 | 0 | memset(&ifr, 0, sizeof(ifr)); |
191 | 0 | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
192 | | #ifdef OS_FREEBSD |
193 | | ifr.ifr_flags = flags & 0xffff; |
194 | | ifr.ifr_flagshigh = flags >> 16; |
195 | | #else |
196 | 0 | ifr.ifr_flags = (uint16_t)flags; |
197 | 0 | #endif |
198 | |
|
199 | 0 | if (ioctl(fd, SIOCSIFFLAGS, &ifr) == -1) { |
200 | 0 | SCLogError("%s: unable to set device flags: %s", ifname, strerror(errno)); |
201 | 0 | close(fd); |
202 | 0 | return -1; |
203 | 0 | } |
204 | | |
205 | 0 | close(fd); |
206 | 0 | return 0; |
207 | 0 | } |
208 | | #endif /* SIOCGIFFLAGS */ |
209 | | |
210 | | #ifdef SIOCGIFCAP |
211 | | int GetIfaceCaps(const char *ifname) |
212 | | { |
213 | | struct ifreq ifr; |
214 | | |
215 | | int fd = socket(AF_INET, SOCK_DGRAM, 0); |
216 | | if (fd < 0) { |
217 | | return -1; |
218 | | } |
219 | | |
220 | | memset(&ifr, 0, sizeof(ifr)); |
221 | | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
222 | | |
223 | | if (ioctl(fd, SIOCGIFCAP, &ifr) == -1) { |
224 | | SCLogError("%s: unable to get device caps: %s", ifname, strerror(errno)); |
225 | | close(fd); |
226 | | return -1; |
227 | | } |
228 | | |
229 | | close(fd); |
230 | | return ifr.ifr_curcap; |
231 | | } |
232 | | #endif |
233 | | #ifdef SIOCSIFCAP |
234 | | int SetIfaceCaps(const char *ifname, int caps) |
235 | | { |
236 | | struct ifreq ifr; |
237 | | |
238 | | int fd = socket(AF_INET, SOCK_DGRAM, 0); |
239 | | if (fd < 0) { |
240 | | return -1; |
241 | | } |
242 | | |
243 | | memset(&ifr, 0, sizeof(ifr)); |
244 | | strlcpy(ifr.ifr_name, ifname, sizeof(ifr.ifr_name)); |
245 | | ifr.ifr_reqcap = caps; |
246 | | |
247 | | if (ioctl(fd, SIOCSIFCAP, &ifr) == -1) { |
248 | | SCLogError("%s: unable to set caps: %s", ifname, strerror(errno)); |
249 | | close(fd); |
250 | | return -1; |
251 | | } |
252 | | |
253 | | close(fd); |
254 | | return 0; |
255 | | } |
256 | | #endif |
257 | | |
258 | | |
259 | | #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL |
260 | | static int GetEthtoolValue(const char *dev, int cmd, uint32_t *value) |
261 | 0 | { |
262 | 0 | struct ifreq ifr; |
263 | 0 | int fd; |
264 | 0 | struct ethtool_value ethv; |
265 | |
|
266 | 0 | fd = socket(AF_INET, SOCK_DGRAM, 0); |
267 | 0 | if (fd == -1) { |
268 | 0 | return -1; |
269 | 0 | } |
270 | 0 | (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); |
271 | |
|
272 | 0 | ethv.cmd = cmd; |
273 | 0 | ifr.ifr_data = (void *) ðv; |
274 | 0 | if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { |
275 | 0 | SCLogWarning("%s: failed to get SIOCETHTOOL ioctl: %s", dev, strerror(errno)); |
276 | 0 | close(fd); |
277 | 0 | return -1; |
278 | 0 | } |
279 | | |
280 | 0 | *value = ethv.data; |
281 | 0 | close(fd); |
282 | 0 | return 0; |
283 | 0 | } |
284 | | |
285 | | static int SetEthtoolValue(const char *dev, int cmd, uint32_t value) |
286 | 0 | { |
287 | 0 | struct ifreq ifr; |
288 | 0 | int fd; |
289 | 0 | struct ethtool_value ethv; |
290 | |
|
291 | 0 | fd = socket(AF_INET, SOCK_DGRAM, 0); |
292 | 0 | if (fd == -1) { |
293 | 0 | return -1; |
294 | 0 | } |
295 | 0 | (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); |
296 | |
|
297 | 0 | ethv.cmd = cmd; |
298 | 0 | ethv.data = value; |
299 | 0 | ifr.ifr_data = (void *) ðv; |
300 | 0 | if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { |
301 | 0 | SCLogWarning("%s: failed to set SIOCETHTOOL ioctl: %s", dev, strerror(errno)); |
302 | 0 | close(fd); |
303 | 0 | return -1; |
304 | 0 | } |
305 | | |
306 | 0 | close(fd); |
307 | 0 | return 0; |
308 | 0 | } |
309 | | |
310 | | static int GetIfaceOffloadingLinux(const char *dev, int csum, int other) |
311 | 0 | { |
312 | 0 | int ret = 0; |
313 | 0 | uint32_t value = 0; |
314 | |
|
315 | 0 | if (csum) { |
316 | 0 | const char *rx = "unset", *tx = "unset"; |
317 | 0 | int csum_ret = 0; |
318 | 0 | #ifdef ETHTOOL_GRXCSUM |
319 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { |
320 | 0 | rx = "SET"; |
321 | 0 | csum_ret = 1; |
322 | 0 | } |
323 | 0 | #endif |
324 | 0 | #ifdef ETHTOOL_GTXCSUM |
325 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { |
326 | 0 | tx = "SET"; |
327 | 0 | csum_ret = 1; |
328 | 0 | } |
329 | 0 | #endif |
330 | 0 | if (csum_ret == 0) |
331 | 0 | SCLogPerf("%s: NIC offloading: RX %s TX %s", dev, rx, tx); |
332 | 0 | else { |
333 | 0 | SCLogWarning("%s: NIC offloading: RX %s TX %s. Run: ethtool -K %s rx off tx off", dev, |
334 | 0 | rx, tx, dev); |
335 | 0 | ret = 1; |
336 | 0 | } |
337 | 0 | } |
338 | |
|
339 | 0 | if (other) { |
340 | 0 | const char *lro = "unset", *gro = "unset", *tso = "unset", *gso = "unset"; |
341 | 0 | const char *sg = "unset"; |
342 | 0 | int other_ret = 0; |
343 | 0 | #ifdef ETHTOOL_GGRO |
344 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { |
345 | 0 | gro = "SET"; |
346 | 0 | other_ret = 1; |
347 | 0 | } |
348 | 0 | #endif |
349 | 0 | #ifdef ETHTOOL_GTSO |
350 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { |
351 | 0 | tso = "SET"; |
352 | 0 | other_ret = 1; |
353 | 0 | } |
354 | 0 | #endif |
355 | 0 | #ifdef ETHTOOL_GGSO |
356 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { |
357 | 0 | gso = "SET"; |
358 | 0 | other_ret = 1; |
359 | 0 | } |
360 | 0 | #endif |
361 | 0 | #ifdef ETHTOOL_GSG |
362 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { |
363 | 0 | sg = "SET"; |
364 | 0 | other_ret = 1; |
365 | 0 | } |
366 | 0 | #endif |
367 | 0 | #ifdef ETHTOOL_GFLAGS |
368 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { |
369 | 0 | if (value & ETH_FLAG_LRO) { |
370 | 0 | lro = "SET"; |
371 | 0 | other_ret = 1; |
372 | 0 | } |
373 | 0 | } |
374 | 0 | #endif |
375 | 0 | if (other_ret == 0) { |
376 | 0 | SCLogPerf("%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s", dev, sg, |
377 | 0 | gro, lro, tso, gso); |
378 | 0 | } else { |
379 | 0 | SCLogWarning("%s: NIC offloading: SG: %s, GRO: %s, LRO: %s, TSO: %s, GSO: %s. Run: " |
380 | 0 | "ethtool -K %s sg off gro off lro off tso off gso off", |
381 | 0 | dev, sg, gro, lro, tso, gso, dev); |
382 | 0 | ret = 1; |
383 | 0 | } |
384 | 0 | } |
385 | 0 | return ret; |
386 | 0 | } |
387 | | |
388 | | static int DisableIfaceOffloadingLinux(LiveDevice *ldev, int csum, int other) |
389 | 0 | { |
390 | 0 | int ret = 0; |
391 | 0 | uint32_t value = 0; |
392 | |
|
393 | 0 | if (ldev == NULL) |
394 | 0 | return -1; |
395 | | |
396 | 0 | const char *dev = ldev->dev; |
397 | |
|
398 | 0 | if (csum) { |
399 | 0 | #ifdef ETHTOOL_GRXCSUM |
400 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GRXCSUM, &value) == 0 && value != 0) { |
401 | 0 | SCLogPerf("%s: disabling rxcsum offloading", dev); |
402 | 0 | SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 0); |
403 | 0 | ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; |
404 | 0 | } |
405 | 0 | #endif |
406 | 0 | #ifdef ETHTOOL_GTXCSUM |
407 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GTXCSUM, &value) == 0 && value != 0) { |
408 | 0 | SCLogPerf("%s: disabling txcsum offloading", dev); |
409 | 0 | SetEthtoolValue(dev, ETHTOOL_STXCSUM, 0); |
410 | 0 | ldev->offload_orig |= OFFLOAD_FLAG_TXCSUM; |
411 | 0 | } |
412 | 0 | #endif |
413 | 0 | } |
414 | 0 | if (other) { |
415 | 0 | #ifdef ETHTOOL_GGRO |
416 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GGRO, &value) == 0 && value != 0) { |
417 | 0 | SCLogPerf("%s: disabling gro offloading", dev); |
418 | 0 | SetEthtoolValue(dev, ETHTOOL_SGRO, 0); |
419 | 0 | ldev->offload_orig |= OFFLOAD_FLAG_GRO; |
420 | 0 | } |
421 | 0 | #endif |
422 | 0 | #ifdef ETHTOOL_GTSO |
423 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GTSO, &value) == 0 && value != 0) { |
424 | 0 | SCLogPerf("%s: disabling tso offloading", dev); |
425 | 0 | SetEthtoolValue(dev, ETHTOOL_STSO, 0); |
426 | 0 | ldev->offload_orig |= OFFLOAD_FLAG_TSO; |
427 | 0 | } |
428 | 0 | #endif |
429 | 0 | #ifdef ETHTOOL_GGSO |
430 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GGSO, &value) == 0 && value != 0) { |
431 | 0 | SCLogPerf("%s: disabling gso offloading", dev); |
432 | 0 | SetEthtoolValue(dev, ETHTOOL_SGSO, 0); |
433 | 0 | ldev->offload_orig |= OFFLOAD_FLAG_GSO; |
434 | 0 | } |
435 | 0 | #endif |
436 | 0 | #ifdef ETHTOOL_GSG |
437 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GSG, &value) == 0 && value != 0) { |
438 | 0 | SCLogPerf("%s: disabling sg offloading", dev); |
439 | 0 | SetEthtoolValue(dev, ETHTOOL_SSG, 0); |
440 | 0 | ldev->offload_orig |= OFFLOAD_FLAG_SG; |
441 | 0 | } |
442 | 0 | #endif |
443 | 0 | #ifdef ETHTOOL_GFLAGS |
444 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { |
445 | 0 | if (value & ETH_FLAG_LRO) { |
446 | 0 | SCLogPerf("%s: disabling lro offloading", dev); |
447 | 0 | SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ~ETH_FLAG_LRO); |
448 | 0 | ldev->offload_orig |= OFFLOAD_FLAG_LRO; |
449 | 0 | } |
450 | 0 | } |
451 | 0 | #endif |
452 | 0 | } |
453 | 0 | return ret; |
454 | 0 | } |
455 | | |
456 | | static int RestoreIfaceOffloadingLinux(LiveDevice *ldev) |
457 | 0 | { |
458 | 0 | if (ldev == NULL) |
459 | 0 | return -1; |
460 | | |
461 | 0 | const char *dev = ldev->dev; |
462 | |
|
463 | 0 | #ifdef ETHTOOL_GRXCSUM |
464 | 0 | if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { |
465 | 0 | SCLogPerf("%s: restoring rxcsum offloading", dev); |
466 | 0 | SetEthtoolValue(dev, ETHTOOL_SRXCSUM, 1); |
467 | 0 | } |
468 | 0 | #endif |
469 | 0 | #ifdef ETHTOOL_GTXCSUM |
470 | 0 | if (ldev->offload_orig & OFFLOAD_FLAG_TXCSUM) { |
471 | 0 | SCLogPerf("%s: restoring txcsum offloading", dev); |
472 | 0 | SetEthtoolValue(dev, ETHTOOL_STXCSUM, 1); |
473 | 0 | } |
474 | 0 | #endif |
475 | 0 | #ifdef ETHTOOL_GGRO |
476 | 0 | if (ldev->offload_orig & OFFLOAD_FLAG_GRO) { |
477 | 0 | SCLogPerf("%s: restoring gro offloading", dev); |
478 | 0 | SetEthtoolValue(dev, ETHTOOL_SGRO, 1); |
479 | 0 | } |
480 | 0 | #endif |
481 | 0 | #ifdef ETHTOOL_GTSO |
482 | 0 | if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { |
483 | 0 | SCLogPerf("%s: restoring tso offloading", dev); |
484 | 0 | SetEthtoolValue(dev, ETHTOOL_STSO, 1); |
485 | 0 | } |
486 | 0 | #endif |
487 | 0 | #ifdef ETHTOOL_GGSO |
488 | 0 | if (ldev->offload_orig & OFFLOAD_FLAG_GSO) { |
489 | 0 | SCLogPerf("%s: restoring gso offloading", dev); |
490 | 0 | SetEthtoolValue(dev, ETHTOOL_SGSO, 1); |
491 | 0 | } |
492 | 0 | #endif |
493 | 0 | #ifdef ETHTOOL_GSG |
494 | 0 | if (ldev->offload_orig & OFFLOAD_FLAG_SG) { |
495 | 0 | SCLogPerf("%s: restoring sg offloading", dev); |
496 | 0 | SetEthtoolValue(dev, ETHTOOL_SSG, 1); |
497 | 0 | } |
498 | 0 | #endif |
499 | 0 | #ifdef ETHTOOL_GFLAGS |
500 | 0 | if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { |
501 | 0 | uint32_t value = 0; |
502 | 0 | if (GetEthtoolValue(dev, ETHTOOL_GFLAGS, &value) == 0) { |
503 | 0 | SCLogPerf("%s: restoring lro offloading", dev); |
504 | 0 | SetEthtoolValue(dev, ETHTOOL_SFLAGS, value & ETH_FLAG_LRO); |
505 | 0 | } |
506 | 0 | } |
507 | 0 | #endif |
508 | 0 | return 0; |
509 | 0 | } |
510 | | |
511 | | #endif /* defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL */ |
512 | | |
513 | | #ifdef SIOCGIFCAP |
514 | | static int GetIfaceOffloadingBSD(const char *ifname) |
515 | | { |
516 | | int ret = 0; |
517 | | int if_caps = GetIfaceCaps(ifname); |
518 | | if (if_caps == -1) { |
519 | | return -1; |
520 | | } |
521 | | SCLogDebug("if_caps %X", if_caps); |
522 | | |
523 | | if (if_caps & IFCAP_RXCSUM) { |
524 | | SCLogWarning("%s: RXCSUM activated can lead to capture problems. Run: ifconfig %s -rxcsum", |
525 | | ifname, ifname); |
526 | | ret = 1; |
527 | | } |
528 | | #ifdef IFCAP_TOE |
529 | | if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { |
530 | | SCLogWarning("%s: TSO, TOE or LRO activated can lead to capture problems. Run: ifconfig %s " |
531 | | "-tso -toe -lro", |
532 | | ifname, ifname); |
533 | | ret = 1; |
534 | | } |
535 | | #else |
536 | | if (if_caps & (IFCAP_TSO|IFCAP_LRO)) { |
537 | | SCLogWarning( |
538 | | "%s: TSO or LRO activated can lead to capture problems. Run: ifconfig %s -tso -lro", |
539 | | ifname, ifname); |
540 | | ret = 1; |
541 | | } |
542 | | #endif |
543 | | return ret; |
544 | | } |
545 | | #endif |
546 | | |
547 | | #ifdef SIOCSIFCAP |
548 | | static int DisableIfaceOffloadingBSD(LiveDevice *ldev) |
549 | | { |
550 | | int ret = 0; |
551 | | |
552 | | if (ldev == NULL) |
553 | | return -1; |
554 | | |
555 | | const char *ifname = ldev->dev; |
556 | | int if_caps = GetIfaceCaps(ifname); |
557 | | int set_caps = if_caps; |
558 | | if (if_caps == -1) { |
559 | | return -1; |
560 | | } |
561 | | SCLogDebug("if_caps %X", if_caps); |
562 | | |
563 | | if (if_caps & IFCAP_RXCSUM) { |
564 | | SCLogPerf("%s: disabling rxcsum offloading", ifname); |
565 | | set_caps &= ~IFCAP_RXCSUM; |
566 | | } |
567 | | if (if_caps & IFCAP_TXCSUM) { |
568 | | SCLogPerf("%s: disabling txcsum offloading", ifname); |
569 | | set_caps &= ~IFCAP_TXCSUM; |
570 | | } |
571 | | #ifdef IFCAP_RXCSUM_IPV6 |
572 | | if (if_caps & IFCAP_RXCSUM_IPV6) { |
573 | | SCLogPerf("%s: disabling rxcsum6 offloading", ifname); |
574 | | set_caps &= ~IFCAP_RXCSUM_IPV6; |
575 | | } |
576 | | #endif |
577 | | #ifdef IFCAP_TXCSUM_IPV6 |
578 | | if (if_caps & IFCAP_TXCSUM_IPV6) { |
579 | | SCLogPerf("%s: disabling txcsum6 offloading", ifname); |
580 | | set_caps &= ~IFCAP_TXCSUM_IPV6; |
581 | | } |
582 | | #endif |
583 | | #ifdef IFCAP_TOE |
584 | | if (if_caps & (IFCAP_TSO|IFCAP_TOE|IFCAP_LRO)) { |
585 | | SCLogPerf("%s: disabling tso|toe|lro offloading", ifname); |
586 | | set_caps &= ~(IFCAP_TSO|IFCAP_LRO); |
587 | | } |
588 | | #else |
589 | | if (if_caps & (IFCAP_TSO|IFCAP_LRO)) { |
590 | | SCLogPerf("%s: disabling tso|lro offloading", ifname); |
591 | | set_caps &= ~(IFCAP_TSO|IFCAP_LRO); |
592 | | } |
593 | | #endif |
594 | | if (set_caps != if_caps) { |
595 | | if (if_caps & IFCAP_RXCSUM) |
596 | | ldev->offload_orig |= OFFLOAD_FLAG_RXCSUM; |
597 | | if (if_caps & IFCAP_TSO) |
598 | | ldev->offload_orig |= OFFLOAD_FLAG_TSO; |
599 | | #ifdef IFCAP_TOE |
600 | | if (if_caps & IFCAP_TOE) |
601 | | ldev->offload_orig |= OFFLOAD_FLAG_TOE; |
602 | | #endif |
603 | | if (if_caps & IFCAP_LRO) |
604 | | ldev->offload_orig |= OFFLOAD_FLAG_LRO; |
605 | | |
606 | | SetIfaceCaps(ifname, set_caps); |
607 | | } |
608 | | return ret; |
609 | | } |
610 | | |
611 | | static int RestoreIfaceOffloadingBSD(LiveDevice *ldev) |
612 | | { |
613 | | int ret = 0; |
614 | | |
615 | | if (ldev == NULL) |
616 | | return -1; |
617 | | |
618 | | const char *ifname = ldev->dev; |
619 | | int if_caps = GetIfaceCaps(ifname); |
620 | | int set_caps = if_caps; |
621 | | if (if_caps == -1) { |
622 | | return -1; |
623 | | } |
624 | | SCLogDebug("if_caps %X", if_caps); |
625 | | |
626 | | if (ldev->offload_orig & OFFLOAD_FLAG_RXCSUM) { |
627 | | SCLogPerf("%s: restoring rxcsum offloading", ifname); |
628 | | set_caps |= IFCAP_RXCSUM; |
629 | | } |
630 | | if (ldev->offload_orig & OFFLOAD_FLAG_TSO) { |
631 | | SCLogPerf("%s: restoring tso offloading", ifname); |
632 | | set_caps |= IFCAP_TSO; |
633 | | } |
634 | | #ifdef IFCAP_TOE |
635 | | if (ldev->offload_orig & OFFLOAD_FLAG_TOE) { |
636 | | SCLogPerf("%s: restoring toe offloading", ifname); |
637 | | set_caps |= IFCAP_TOE; |
638 | | } |
639 | | #endif |
640 | | if (ldev->offload_orig & OFFLOAD_FLAG_LRO) { |
641 | | SCLogPerf("%s: restoring lro offloading", ifname); |
642 | | set_caps |= IFCAP_LRO; |
643 | | } |
644 | | |
645 | | if (set_caps != if_caps) { |
646 | | SetIfaceCaps(ifname, set_caps); |
647 | | } |
648 | | return ret; |
649 | | } |
650 | | #endif |
651 | | |
652 | | /** |
653 | | * \brief output offloading status of the link |
654 | | * |
655 | | * Test interface for offloading features. If one of them is |
656 | | * activated then suricata mays received packets merge at reception. |
657 | | * The result is oversized packets and this may cause some serious |
658 | | * problem in some capture mode where the size of the packet is |
659 | | * limited (AF_PACKET in V2 more for example). |
660 | | * |
661 | | * \param Name of link |
662 | | * \param csum check if checksums are offloaded |
663 | | * \param other check if other things are offloaded: TSO, GRO, etc. |
664 | | * \retval -1 in case of error, 0 if none, 1 if some |
665 | | */ |
666 | | int GetIfaceOffloading(const char *dev, int csum, int other) |
667 | 0 | { |
668 | 0 | #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL |
669 | 0 | return GetIfaceOffloadingLinux(dev, csum, other); |
670 | | #elif defined SIOCGIFCAP |
671 | | return GetIfaceOffloadingBSD(dev); |
672 | | #elif defined OS_WIN32 |
673 | | return GetIfaceOffloadingWin32(dev, csum, other); |
674 | | #else |
675 | | return 0; |
676 | | #endif |
677 | 0 | } |
678 | | |
679 | | int DisableIfaceOffloading(LiveDevice *dev, int csum, int other) |
680 | 0 | { |
681 | | /* already set */ |
682 | 0 | if (dev->offload_orig != 0) |
683 | 0 | return 0; |
684 | 0 | #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL |
685 | 0 | return DisableIfaceOffloadingLinux(dev, csum, other); |
686 | | #elif defined SIOCSIFCAP |
687 | | return DisableIfaceOffloadingBSD(dev); |
688 | | #elif defined OS_WIN32 |
689 | | return DisableIfaceOffloadingWin32(dev, csum, other); |
690 | | #else |
691 | | return 0; |
692 | | #endif |
693 | |
|
694 | 0 | } |
695 | | |
696 | | void RestoreIfaceOffloading(LiveDevice *dev) |
697 | 0 | { |
698 | 0 | if (dev->offload_orig != 0) { |
699 | 0 | #if defined HAVE_LINUX_ETHTOOL_H && defined SIOCETHTOOL |
700 | 0 | RestoreIfaceOffloadingLinux(dev); |
701 | | #elif defined SIOCSIFCAP |
702 | | RestoreIfaceOffloadingBSD(dev); |
703 | | #elif defined OS_WIN32 |
704 | | RestoreIfaceOffloadingWin32(dev); |
705 | | #endif |
706 | 0 | } |
707 | 0 | } |
708 | | |
709 | | int GetIfaceRSSQueuesNum(const char *dev) |
710 | 0 | { |
711 | 0 | #if defined HAVE_LINUX_ETHTOOL_H && defined ETHTOOL_GRXRINGS |
712 | 0 | struct ifreq ifr; |
713 | 0 | struct ethtool_rxnfc nfccmd; |
714 | 0 | int fd; |
715 | |
|
716 | 0 | (void)strlcpy(ifr.ifr_name, dev, sizeof(ifr.ifr_name)); |
717 | 0 | fd = socket(AF_INET, SOCK_DGRAM, 0); |
718 | 0 | if (fd == -1) { |
719 | 0 | SCLogWarning("%s: failed to open socket for ioctl: %s", dev, strerror(errno)); |
720 | 0 | return -1; |
721 | 0 | } |
722 | | |
723 | 0 | nfccmd.cmd = ETHTOOL_GRXRINGS; |
724 | 0 | ifr.ifr_data = (void*) &nfccmd; |
725 | |
|
726 | 0 | if (ioctl(fd, SIOCETHTOOL, (char *)&ifr) < 0) { |
727 | 0 | if (errno != ENOTSUP) { |
728 | 0 | SCLogWarning("%s: failed get number of RSS queue ioctl: %s", dev, strerror(errno)); |
729 | 0 | } |
730 | 0 | close(fd); |
731 | 0 | return 0; |
732 | 0 | } |
733 | 0 | close(fd); |
734 | 0 | SCLogInfo("%s: RX RSS queues: %d", dev, (int)nfccmd.data); |
735 | 0 | return (int)nfccmd.data; |
736 | | #else |
737 | | return 0; |
738 | | #endif |
739 | 0 | } |