suricata
util-affinity.c
Go to the documentation of this file.
1 /* Copyright (C) 2010-2016 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 /** \file
19  *
20  * \author Eric Leblond <eric@regit.org>
21  *
22  * CPU affinity related code and helper.
23  */
24 
25 #include "suricata-common.h"
26 #define _THREAD_AFFINITY
27 #include "util-affinity.h"
28 #include "util-cpu.h"
29 #include "util-byte.h"
30 #include "conf.h"
31 #include "threads.h"
32 #include "queue.h"
33 #include "runmodes.h"
34 
36  {
37  .name = "receive-cpu-set",
38  .mode_flag = EXCLUSIVE_AFFINITY,
39  .prio = PRIO_MEDIUM,
40  .lcpu = 0,
41  },
42  {
43  .name = "worker-cpu-set",
44  .mode_flag = EXCLUSIVE_AFFINITY,
45  .prio = PRIO_MEDIUM,
46  .lcpu = 0,
47  },
48  {
49  .name = "verdict-cpu-set",
50  .mode_flag = BALANCED_AFFINITY,
51  .prio = PRIO_MEDIUM,
52  .lcpu = 0,
53  },
54  {
55  .name = "management-cpu-set",
56  .mode_flag = BALANCED_AFFINITY,
57  .prio = PRIO_MEDIUM,
58  .lcpu = 0,
59  },
60 
61 };
62 
64 
65 /**
66  * \brief find affinity by its name
67  * \retval a pointer to the affinity or NULL if not found
68  */
70 {
71  int i;
72  for (i = 0; i < MAX_CPU_SET; i++) {
73  if (!strcmp(thread_affinity[i].name, name)) {
74  return &thread_affinity[i];
75  }
76  }
77  return NULL;
78 }
79 
80 #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun
81 static void AffinitySetupInit(void)
82 {
83  int i, j;
85 
86  SCLogDebug("Initialize affinity setup\n");
87  /* be conservative relatively to OS: use all cpus by default */
88  for (i = 0; i < MAX_CPU_SET; i++) {
89  cpu_set_t *cs = &thread_affinity[i].cpu_set;
90  CPU_ZERO(cs);
91  for (j = 0; j < ncpu; j++) {
92  CPU_SET(j, cs);
93  }
94  SCMutexInit(&thread_affinity[i].taf_mutex, NULL);
95  }
96  return;
97 }
98 
99 void BuildCpusetWithCallback(const char *name, ConfNode *node,
100  void (*Callback)(int i, void * data),
101  void *data)
102 {
103  ConfNode *lnode;
104  TAILQ_FOREACH(lnode, &node->head, next) {
105  int i;
106  long int a,b;
107  int stop = 0;
108  int max = UtilCpuGetNumProcessorsOnline() - 1;
109  if (!strcmp(lnode->val, "all")) {
110  a = 0;
111  b = max;
112  stop = 1;
113  } else if (strchr(lnode->val, '-') != NULL) {
114  char *sep = strchr(lnode->val, '-');
115  char *end;
116  a = strtoul(lnode->val, &end, 10);
117  if (end != sep) {
119  "%s: invalid cpu range (start invalid): \"%s\"",
120  name,
121  lnode->val);
122  exit(EXIT_FAILURE);
123  }
124  b = strtol(sep + 1, &end, 10);
125  if (end != sep + strlen(sep)) {
127  "%s: invalid cpu range (end invalid): \"%s\"",
128  name,
129  lnode->val);
130  exit(EXIT_FAILURE);
131  }
132  if (a > b) {
134  "%s: invalid cpu range (bad order): \"%s\"",
135  name,
136  lnode->val);
137  exit(EXIT_FAILURE);
138  }
139  if (b > max) {
141  "%s: upper bound (%ld) of cpu set is too high, only %d cpu(s)",
142  name,
143  b, max + 1);
144  }
145  } else {
146  char *end;
147  a = strtoul(lnode->val, &end, 10);
148  if (end != lnode->val + strlen(lnode->val)) {
150  "%s: invalid cpu range (not an integer): \"%s\"",
151  name,
152  lnode->val);
153  exit(EXIT_FAILURE);
154  }
155  b = a;
156  }
157  for (i = a; i<= b; i++) {
158  Callback(i, data);
159  }
160  if (stop)
161  break;
162  }
163 }
164 
165 static void AffinityCallback(int i, void *data)
166 {
167  CPU_SET(i, (cpu_set_t *)data);
168 }
169 
170 static void BuildCpuset(const char *name, ConfNode *node, cpu_set_t *cpu)
171 {
172  BuildCpusetWithCallback(name, node, AffinityCallback, (void *) cpu);
173 }
174 #endif /* OS_WIN32 and __OpenBSD__ */
175 
176 /**
177  * \brief Extract cpu affinity configuration from current config file
178  */
179 
181 {
182 #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun
183  ConfNode *root = ConfGetNode("threading.cpu-affinity");
184  ConfNode *affinity;
185 
186  if (thread_affinity_init_done == 0) {
187  AffinitySetupInit();
189  }
190 
191  SCLogDebug("Load affinity from config\n");
192  if (root == NULL) {
193  SCLogInfo("can't get cpu-affinity node");
194  return;
195  }
196 
197  TAILQ_FOREACH(affinity, &root->head, next) {
198  if (strcmp(affinity->val, "decode-cpu-set") == 0 ||
199  strcmp(affinity->val, "stream-cpu-set") == 0 ||
200  strcmp(affinity->val, "reject-cpu-set") == 0 ||
201  strcmp(affinity->val, "output-cpu-set") == 0) {
202  continue;
203  }
204 
205  const char *setname = affinity->val;
206  if (strcmp(affinity->val, "detect-cpu-set") == 0)
207  setname = "worker-cpu-set";
208 
210  ConfNode *node = NULL;
211  ConfNode *nprio = NULL;
212 
213  if (taf == NULL) {
214  SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown cpu-affinity type");
215  exit(EXIT_FAILURE);
216  } else {
217  SCLogConfig("Found affinity definition for \"%s\"", setname);
218  }
219 
220  CPU_ZERO(&taf->cpu_set);
221  node = ConfNodeLookupChild(affinity->head.tqh_first, "cpu");
222  if (node == NULL) {
223  SCLogInfo("unable to find 'cpu'");
224  } else {
225  BuildCpuset(setname, node, &taf->cpu_set);
226  }
227 
228  CPU_ZERO(&taf->lowprio_cpu);
229  CPU_ZERO(&taf->medprio_cpu);
230  CPU_ZERO(&taf->hiprio_cpu);
231  nprio = ConfNodeLookupChild(affinity->head.tqh_first, "prio");
232  if (nprio != NULL) {
233  node = ConfNodeLookupChild(nprio, "low");
234  if (node == NULL) {
235  SCLogDebug("unable to find 'low' prio using default value");
236  } else {
237  BuildCpuset(setname, node, &taf->lowprio_cpu);
238  }
239 
240  node = ConfNodeLookupChild(nprio, "medium");
241  if (node == NULL) {
242  SCLogDebug("unable to find 'medium' prio using default value");
243  } else {
244  BuildCpuset(setname, node, &taf->medprio_cpu);
245  }
246 
247  node = ConfNodeLookupChild(nprio, "high");
248  if (node == NULL) {
249  SCLogDebug("unable to find 'high' prio using default value");
250  } else {
251  BuildCpuset(setname, node, &taf->hiprio_cpu);
252  }
253  node = ConfNodeLookupChild(nprio, "default");
254  if (node != NULL) {
255  if (!strcmp(node->val, "low")) {
256  taf->prio = PRIO_LOW;
257  } else if (!strcmp(node->val, "medium")) {
258  taf->prio = PRIO_MEDIUM;
259  } else if (!strcmp(node->val, "high")) {
260  taf->prio = PRIO_HIGH;
261  } else {
262  SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown cpu_affinity prio");
263  exit(EXIT_FAILURE);
264  }
265  SCLogConfig("Using default prio '%s' for set '%s'",
266  node->val, setname);
267  }
268  }
269 
270  node = ConfNodeLookupChild(affinity->head.tqh_first, "mode");
271  if (node != NULL) {
272  if (!strcmp(node->val, "exclusive")) {
274  } else if (!strcmp(node->val, "balanced")) {
276  } else {
277  SCLogError(SC_ERR_INVALID_ARGUMENT, "unknown cpu_affinity node");
278  exit(EXIT_FAILURE);
279  }
280  }
281 
282  node = ConfNodeLookupChild(affinity->head.tqh_first, "threads");
283  if (node != NULL) {
284  if (StringParseUint32(&taf->nb_threads, 10, 0, (const char *)node->val) < 0) {
285  FatalError(SC_ERR_INVALID_ARGUMENT, "invalid value for threads "
286  "count: '%s'", node->val);
287  }
288  if (! taf->nb_threads) {
289  SCLogError(SC_ERR_INVALID_ARGUMENT, "bad value for threads count");
290  exit(EXIT_FAILURE);
291  }
292  }
293  }
294 #endif /* OS_WIN32 and __OpenBSD__ */
295 }
296 
297 /**
298  * \brief Return next cpu to use for a given thread family
299  * \retval the cpu to used given by its id
300  */
302 {
303  int ncpu = 0;
304 #if !defined __CYGWIN__ && !defined OS_WIN32 && !defined __OpenBSD__ && !defined sun
305  int iter = 0;
306  SCMutexLock(&taf->taf_mutex);
307  ncpu = taf->lcpu;
308  while (!CPU_ISSET(ncpu, &taf->cpu_set) && iter < 2) {
309  ncpu++;
310  if (ncpu >= UtilCpuGetNumProcessorsOnline()) {
311  ncpu = 0;
312  iter++;
313  }
314  }
315  if (iter == 2) {
316  SCLogError(SC_ERR_INVALID_ARGUMENT, "cpu_set does not contain "
317  "available cpus, cpu affinity conf is invalid");
318  }
319  taf->lcpu = ncpu + 1;
320  if (taf->lcpu >= UtilCpuGetNumProcessorsOnline())
321  taf->lcpu = 0;
322  SCMutexUnlock(&taf->taf_mutex);
323  SCLogDebug("Setting affinity on CPU %d", ncpu);
324 #endif /* OS_WIN32 and __OpenBSD__ */
325  return ncpu;
326 }
ThreadsAffinityType_::medprio_cpu
cpu_set_t medprio_cpu
Definition: util-affinity.h:75
util-byte.h
ThreadsAffinityType_::nb_threads
uint32_t nb_threads
Definition: util-affinity.h:68
ThreadsAffinityType_::lcpu
uint16_t lcpu
Definition: util-affinity.h:70
EXCLUSIVE_AFFINITY
@ EXCLUSIVE_AFFINITY
Definition: util-affinity.h:60
ConfNode_::val
char * val
Definition: conf.h:34
MAX_CPU_SET
@ MAX_CPU_SET
Definition: util-affinity.h:55
SCLogDebug
#define SCLogDebug(...)
Definition: util-debug.h:298
next
struct HtpBodyChunk_ * next
Definition: app-layer-htp.h:0
ThreadsAffinityType_::lowprio_cpu
cpu_set_t lowprio_cpu
Definition: util-affinity.h:74
ConfGetNode
ConfNode * ConfGetNode(const char *name)
Get a ConfNode by name.
Definition: conf.c:176
threads.h
BuildCpusetWithCallback
void BuildCpusetWithCallback(const char *name, ConfNode *node, void(*Callback)(int i, void *data), void *data)
Definition: util-affinity.c:99
UtilCpuGetNumProcessorsConfigured
uint16_t UtilCpuGetNumProcessorsConfigured(void)
Get the number of cpus configured in the system.
Definition: util-cpu.c:59
AffinityGetNextCPU
int AffinityGetNextCPU(ThreadsAffinityType *taf)
Return next cpu to use for a given thread family.
Definition: util-affinity.c:301
TAILQ_FOREACH
#define TAILQ_FOREACH(var, head, field)
Definition: queue.h:350
SCMutexLock
#define SCMutexLock(mut)
Definition: threads-debug.h:117
PRIO_LOW
@ PRIO_LOW
Definition: threads.h:94
PRIO_MEDIUM
@ PRIO_MEDIUM
Definition: threads.h:95
BALANCED_AFFINITY
@ BALANCED_AFFINITY
Definition: util-affinity.h:59
util-cpu.h
ThreadsAffinityType_::hiprio_cpu
cpu_set_t hiprio_cpu
Definition: util-affinity.h:76
SCMutexUnlock
#define SCMutexUnlock(mut)
Definition: threads-debug.h:119
util-affinity.h
SC_ERR_INVALID_ARGUMENT
@ SC_ERR_INVALID_ARGUMENT
Definition: util-error.h:43
conf.h
ThreadsAffinityType_::cpu_set
cpu_set_t cpu_set
Definition: util-affinity.h:73
ThreadsAffinityType_::mode_flag
uint8_t mode_flag
Definition: util-affinity.h:66
queue.h
runmodes.h
SCLogInfo
#define SCLogInfo(...)
Macro used to log INFORMATIONAL messages.
Definition: util-debug.h:217
SCMutexInit
#define SCMutexInit(mut, mutattrs)
Definition: threads-debug.h:116
PRIO_HIGH
@ PRIO_HIGH
Definition: threads.h:96
ConfNodeLookupChild
ConfNode * ConfNodeLookupChild(const ConfNode *node, const char *name)
Lookup a child configuration node by name.
Definition: conf.c:815
StringParseUint32
int StringParseUint32(uint32_t *res, int base, uint16_t len, const char *str)
Definition: util-byte.c:313
ThreadsAffinityType_::name
const char * name
Definition: util-affinity.h:65
suricata-common.h
thread_affinity
ThreadsAffinityType thread_affinity[MAX_CPU_SET]
Definition: util-affinity.c:35
SCLogError
#define SCLogError(err_code,...)
Macro used to log ERROR messages.
Definition: util-debug.h:257
FatalError
#define FatalError(x,...)
Definition: util-debug.h:532
AffinitySetupLoadFromConfig
void AffinitySetupLoadFromConfig()
Extract cpu affinity configuration from current config file.
Definition: util-affinity.c:180
ThreadsAffinityType_
Definition: util-affinity.h:64
SCLogConfig
struct SCLogConfig_ SCLogConfig
Holds the config state used by the logging api.
ConfNode_
Definition: conf.h:32
thread_affinity_init_done
int thread_affinity_init_done
Definition: util-affinity.c:63
ThreadsAffinityType_::taf_mutex
SCMutex taf_mutex
Definition: util-affinity.h:69
GetAffinityTypeFromName
ThreadsAffinityType * GetAffinityTypeFromName(const char *name)
find affinity by its name
Definition: util-affinity.c:69
ThreadsAffinityType_::prio
int prio
Definition: util-affinity.h:67
UtilCpuGetNumProcessorsOnline
uint16_t UtilCpuGetNumProcessorsOnline(void)
Get the number of cpus online in the system.
Definition: util-cpu.c:106