/src/suricata7/src/runmode-napatech.c
Line | Count | Source |
1 | | /* Copyright (C) 2012-2017 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 nPulse Technologies, LLC. |
22 | | * \author Matt Keeler <mk@npulsetech.com> |
23 | | */ |
24 | | |
25 | | #include "suricata-common.h" |
26 | | #include "tm-threads.h" |
27 | | #include "conf.h" |
28 | | #include "runmodes.h" |
29 | | #include "output.h" |
30 | | #include "util-debug.h" |
31 | | #include "util-time.h" |
32 | | #include "util-cpu.h" |
33 | | #include "util-byte.h" |
34 | | #include "util-affinity.h" |
35 | | #include "util-runmodes.h" |
36 | | #include "util-device.h" |
37 | | #include "util-napatech.h" |
38 | | #include "runmode-napatech.h" |
39 | | #include "source-napatech.h" // need NapatechStreamDevConf structure |
40 | | |
41 | | #define NT_RUNMODE_AUTOFP 1 |
42 | | #define NT_RUNMODE_WORKERS 2 |
43 | | |
44 | | static const char *default_mode = "workers"; |
45 | | |
46 | | #ifdef HAVE_NAPATECH |
47 | | |
48 | | #define MAX_STREAMS 256 |
49 | | static uint16_t num_configured_streams = 0; |
50 | | static uint16_t first_stream = 0xffff; |
51 | | static uint16_t last_stream = 0xffff; |
52 | | static int auto_config = 0; |
53 | | static int use_hw_bypass = 0; |
54 | | |
55 | | uint16_t NapatechGetNumConfiguredStreams(void) |
56 | | { |
57 | | return num_configured_streams; |
58 | | } |
59 | | |
60 | | uint16_t NapatechGetNumFirstStream(void) |
61 | | { |
62 | | return first_stream; |
63 | | } |
64 | | |
65 | | uint16_t NapatechGetNumLastStream(void) |
66 | | { |
67 | | return last_stream; |
68 | | } |
69 | | |
70 | | bool NapatechIsAutoConfigEnabled(void) |
71 | | { |
72 | | return (auto_config != 0); |
73 | | } |
74 | | |
75 | | bool NapatechUseHWBypass(void) |
76 | | { |
77 | | return (use_hw_bypass != 0); |
78 | | } |
79 | | |
80 | | #endif |
81 | | |
82 | | const char *RunModeNapatechGetDefaultMode(void) |
83 | 0 | { |
84 | 0 | return default_mode; |
85 | 0 | } |
86 | | |
87 | | void RunModeNapatechRegister(void) |
88 | 37 | { |
89 | | #ifdef HAVE_NAPATECH |
90 | | RunModeRegisterNewRunMode(RUNMODE_NAPATECH, "workers", |
91 | | "Workers Napatech mode, each thread does all" |
92 | | " tasks from acquisition to logging", |
93 | | RunModeNapatechWorkers, NULL); |
94 | | return; |
95 | | #endif |
96 | 37 | } |
97 | | |
98 | | |
99 | | #ifdef HAVE_NAPATECH |
100 | | |
101 | | static int NapatechRegisterDeviceStreams(void) |
102 | | { |
103 | | /* Display the configuration mode */ |
104 | | int use_all_streams; |
105 | | |
106 | | if (ConfGetBool("napatech.use-all-streams", &use_all_streams) == 0) { |
107 | | SCLogInfo("Could not find napatech.use-all-streams in config file. Defaulting to \"no\"."); |
108 | | use_all_streams = 0; |
109 | | } |
110 | | |
111 | | if (ConfGetBool("napatech.auto-config", &auto_config) == 0) { |
112 | | SCLogInfo("napatech.auto-config not found in config file. Defaulting to disabled."); |
113 | | } |
114 | | |
115 | | if (ConfGetBool("napatech.hardware-bypass", &use_hw_bypass) == 0) { |
116 | | SCLogInfo("napatech.hardware-bypass not found in config file. Defaulting to disabled."); |
117 | | } |
118 | | |
119 | | /* use_all_streams uses existing streams created prior to starting Suricata. auto_config |
120 | | * automatically creates streams. Therefore, these two options are mutually exclusive. |
121 | | */ |
122 | | if (use_all_streams && auto_config) { |
123 | | FatalError("napatech.auto-config cannot be used in configuration file at the same time as " |
124 | | "napatech.use-all-streams."); |
125 | | } |
126 | | |
127 | | /* to use hardware_bypass we need to configure the streams to be consistent. |
128 | | * with the rest of the configuration. Therefore auto_config is not a valid |
129 | | * option. |
130 | | */ |
131 | | if (use_hw_bypass && auto_config == 0) { |
132 | | FatalError("napatech auto-config must be enabled when using napatech.use_hw_bypass."); |
133 | | } |
134 | | |
135 | | /* Get the stream ID's either from the conf or by querying Napatech */ |
136 | | NapatechStreamConfig stream_config[MAX_STREAMS]; |
137 | | |
138 | | uint16_t stream_cnt = NapatechGetStreamConfig(stream_config); |
139 | | num_configured_streams = stream_cnt; |
140 | | SCLogDebug("Configuring %d Napatech Streams...", stream_cnt); |
141 | | |
142 | | for (uint16_t inst = 0; inst < stream_cnt; ++inst) { |
143 | | char *plive_dev_buf = SCCalloc(1, 9); |
144 | | if (unlikely(plive_dev_buf == NULL)) { |
145 | | FatalError("Failed to allocate memory for NAPATECH stream counter."); |
146 | | } |
147 | | snprintf(plive_dev_buf, 9, "nt%d", stream_config[inst].stream_id); |
148 | | |
149 | | if (auto_config) { |
150 | | if (stream_config[inst].is_active) { |
151 | | SCLogError("Registering Napatech device: %s - active stream found.", plive_dev_buf); |
152 | | SCLogError( |
153 | | "run /opt/napatech3/bin/ntpl -e \"delete=all\" to delete existing stream"); |
154 | | FatalError("or disable auto-config in the conf file before running."); |
155 | | } |
156 | | } else { |
157 | | SCLogInfo("Registering Napatech device: %s - active stream%sfound.", |
158 | | plive_dev_buf, stream_config[inst].is_active ? " " : " NOT "); |
159 | | } |
160 | | LiveRegisterDevice(plive_dev_buf); |
161 | | |
162 | | if (first_stream == 0xffff) { |
163 | | first_stream = stream_config[inst].stream_id; |
164 | | } |
165 | | last_stream = stream_config[inst].stream_id; |
166 | | } |
167 | | |
168 | | /* Napatech stats come from a separate thread. This will suppress |
169 | | * the counters when suricata exits. |
170 | | */ |
171 | | LiveDeviceHasNoStats(); |
172 | | return 0; |
173 | | } |
174 | | |
175 | | static void *NapatechConfigParser(const char *device) |
176 | | { |
177 | | /* Expect device to be of the form nt%d where %d is the stream id to use */ |
178 | | int dev_len = strlen(device); |
179 | | if (dev_len < 3 || dev_len > 5) { |
180 | | SCLogError("Could not parse config for device: %s - invalid length", device); |
181 | | return NULL; |
182 | | } |
183 | | |
184 | | struct NapatechStreamDevConf *conf = SCCalloc(1, sizeof (struct NapatechStreamDevConf)); |
185 | | if (unlikely(conf == NULL)) { |
186 | | SCLogError("Failed to allocate memory for NAPATECH device name."); |
187 | | return NULL; |
188 | | } |
189 | | |
190 | | /* device+2 is a pointer to the beginning of the stream id after the constant nt portion */ |
191 | | if (StringParseUint16(&conf->stream_id, 10, 0, device + 2) < 0) { |
192 | | SCLogError("Invalid value for stream_id: %s", device + 2); |
193 | | SCFree(conf); |
194 | | return NULL; |
195 | | } |
196 | | |
197 | | /* Set the host buffer allowance for this stream |
198 | | * Right now we just look at the global default - there is no per-stream hba configuration |
199 | | */ |
200 | | if (ConfGetInt("napatech.hba", &conf->hba) == 0) { |
201 | | conf->hba = -1; |
202 | | } else { |
203 | | static bool warn_once = false; |
204 | | if (!warn_once) { |
205 | | SCLogWarning( |
206 | | "Napatech Host Buffer Allowance (hba) will be deprecated in Suricata v8.0."); |
207 | | warn_once = true; |
208 | | } |
209 | | } |
210 | | return (void *) conf; |
211 | | } |
212 | | |
213 | | static int NapatechGetThreadsCount(void *conf __attribute__((unused))) |
214 | | { |
215 | | /* No matter which live device it is there is no reason to ever use more than 1 thread |
216 | | 2 or more thread would cause packet duplication */ |
217 | | return 1; |
218 | | } |
219 | | |
220 | | static int NapatechInit(int runmode) |
221 | | { |
222 | | int status; |
223 | | |
224 | | TimeModeSetLive(); |
225 | | |
226 | | /* Initialize the API and check version compatibility */ |
227 | | if ((status = NT_Init(NTAPI_VERSION)) != NT_SUCCESS) { |
228 | | NAPATECH_ERROR(status); |
229 | | exit(EXIT_FAILURE); |
230 | | } |
231 | | |
232 | | status = NapatechRegisterDeviceStreams(); |
233 | | if (status < 0 || num_configured_streams <= 0) { |
234 | | FatalError("Unable to find existing Napatech Streams"); |
235 | | } |
236 | | |
237 | | struct NapatechStreamDevConf *conf = |
238 | | SCCalloc(1, sizeof (struct NapatechStreamDevConf)); |
239 | | if (unlikely(conf == NULL)) { |
240 | | FatalError("Failed to allocate memory for NAPATECH device."); |
241 | | } |
242 | | |
243 | | if ((ConfGetInt("napatech.hba", &conf->hba) != 0) && (conf->hba > 0)) { |
244 | | SCLogInfo("Host Buffer Allowance: %d", (int) conf->hba); |
245 | | } |
246 | | |
247 | | if (use_hw_bypass) { |
248 | | #ifdef NAPATECH_ENABLE_BYPASS |
249 | | if (NapatechVerifyBypassSupport()) { |
250 | | SCLogInfo("Napatech Hardware Bypass is supported and enabled."); |
251 | | } else { |
252 | | FatalError("Napatech Hardware Bypass requested in conf but is not supported by the " |
253 | | "hardware."); |
254 | | } |
255 | | #else |
256 | | FatalError( |
257 | | "Napatech Hardware Bypass requested in conf but is not enabled by the software."); |
258 | | #endif |
259 | | } else { |
260 | | SCLogInfo("Hardware Bypass is disabled in the conf file."); |
261 | | } |
262 | | |
263 | | /* Start a thread to process the statistics */ |
264 | | NapatechStartStats(); |
265 | | |
266 | | switch (runmode) { |
267 | | case NT_RUNMODE_WORKERS: |
268 | | status = RunModeSetLiveCaptureWorkers(NapatechConfigParser, NapatechGetThreadsCount, |
269 | | "NapatechStream", "NapatechDecode", thread_name_workers, NULL); |
270 | | break; |
271 | | default: |
272 | | status = -1; |
273 | | } |
274 | | |
275 | | if (status != 0) { |
276 | | FatalError("Runmode start failed"); |
277 | | } |
278 | | return 0; |
279 | | } |
280 | | |
281 | | int RunModeNapatechAutoFp(void) |
282 | | { |
283 | | return NapatechInit(NT_RUNMODE_AUTOFP); |
284 | | } |
285 | | |
286 | | int RunModeNapatechWorkers(void) |
287 | | { |
288 | | return NapatechInit(NT_RUNMODE_WORKERS); |
289 | | } |
290 | | |
291 | | #endif |