1 /*
2 * nwfilter_params.c: parsing and data maintenance of filter parameters
3 *
4 * Copyright (C) 2011-2014 Red Hat, Inc.
5 * Copyright (C) 2010 IBM Corporation
6 *
7 * This library is free software; you can redistribute it and/or
8 * modify it under the terms of the GNU Lesser General Public
9 * License as published by the Free Software Foundation; either
10 * version 2.1 of the License, or (at your option) any later version.
11 *
12 * This library is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * Lesser General Public License for more details.
16 *
17 * You should have received a copy of the GNU Lesser General Public
18 * License along with this library. If not, see
19 * <http://www.gnu.org/licenses/>.
20 */
21
22 #include <config.h>
23
24 #include "internal.h"
25
26 #include "viralloc.h"
27 #include "virerror.h"
28 #include "datatypes.h"
29 #include "nwfilter_params.h"
30 #include "domain_conf.h"
31 #include "virlog.h"
32 #include "virstring.h"
33
34 #define VIR_FROM_THIS VIR_FROM_NWFILTER
35
36 VIR_LOG_INIT("conf.nwfilter_params");
37
38 static bool isValidVarValue(const char *value);
39 static void virNWFilterVarAccessSetIntIterId(virNWFilterVarAccess *,
40 unsigned int);
41 static unsigned int virNWFilterVarAccessGetIntIterId(const virNWFilterVarAccess *);
42
43 void
virNWFilterVarValueFree(virNWFilterVarValue * val)44 virNWFilterVarValueFree(virNWFilterVarValue *val)
45 {
46 size_t i;
47
48 if (!val)
49 return;
50
51 switch (val->valType) {
52 case NWFILTER_VALUE_TYPE_SIMPLE:
53 g_free(val->u.simple.value);
54 break;
55 case NWFILTER_VALUE_TYPE_ARRAY:
56 for (i = 0; i < val->u.array.nValues; i++)
57 g_free(val->u.array.values[i]);
58 g_free(val->u.array.values);
59 break;
60 case NWFILTER_VALUE_TYPE_LAST:
61 break;
62 }
63 g_free(val);
64 }
65
66 virNWFilterVarValue *
virNWFilterVarValueCopy(const virNWFilterVarValue * val)67 virNWFilterVarValueCopy(const virNWFilterVarValue *val)
68 {
69 virNWFilterVarValue *res;
70 size_t i;
71 char *str;
72
73 res = g_new0(virNWFilterVarValue, 1);
74 res->valType = val->valType;
75
76 switch (res->valType) {
77 case NWFILTER_VALUE_TYPE_SIMPLE:
78 res->u.simple.value = g_strdup(val->u.simple.value);
79 break;
80 case NWFILTER_VALUE_TYPE_ARRAY:
81 res->u.array.values = g_new0(char *, val->u.array.nValues);
82 res->u.array.nValues = val->u.array.nValues;
83 for (i = 0; i < val->u.array.nValues; i++) {
84 str = g_strdup(val->u.array.values[i]);
85 res->u.array.values[i] = str;
86 }
87 break;
88 case NWFILTER_VALUE_TYPE_LAST:
89 break;
90 }
91
92 return res;
93 }
94
95 virNWFilterVarValue *
virNWFilterVarValueCreateSimple(char * value)96 virNWFilterVarValueCreateSimple(char *value)
97 {
98 virNWFilterVarValue *val;
99
100 if (!isValidVarValue(value)) {
101 virReportError(VIR_ERR_INVALID_ARG, "%s",
102 _("Variable value contains invalid character"));
103 return NULL;
104 }
105
106 val = g_new0(virNWFilterVarValue, 1);
107
108 val->valType = NWFILTER_VALUE_TYPE_SIMPLE;
109 val->u.simple.value = value;
110
111 return val;
112 }
113
114 virNWFilterVarValue *
virNWFilterVarValueCreateSimpleCopyValue(const char * value)115 virNWFilterVarValueCreateSimpleCopyValue(const char *value)
116 {
117 char *val;
118 virNWFilterVarValue *ret;
119
120 val = g_strdup(value);
121 ret = virNWFilterVarValueCreateSimple(val);
122 if (!ret)
123 VIR_FREE(val);
124 return ret;
125 }
126
127 const char *
virNWFilterVarValueGetSimple(const virNWFilterVarValue * val)128 virNWFilterVarValueGetSimple(const virNWFilterVarValue *val)
129 {
130 if (val->valType == NWFILTER_VALUE_TYPE_SIMPLE)
131 return val->u.simple.value;
132 return NULL;
133 }
134
135 const char *
virNWFilterVarValueGetNthValue(const virNWFilterVarValue * val,unsigned int idx)136 virNWFilterVarValueGetNthValue(const virNWFilterVarValue* val, unsigned int idx)
137 {
138 const char *res = NULL;
139
140 if (!val)
141 return NULL;
142
143 switch (val->valType) {
144 case NWFILTER_VALUE_TYPE_SIMPLE:
145 if (idx == 0)
146 res = val->u.simple.value;
147 break;
148 case NWFILTER_VALUE_TYPE_ARRAY:
149 if (idx < val->u.array.nValues)
150 res = val->u.array.values[idx];
151 break;
152 case NWFILTER_VALUE_TYPE_LAST:
153 break;
154 }
155
156 return res;
157 }
158
159 unsigned int
virNWFilterVarValueGetCardinality(const virNWFilterVarValue * val)160 virNWFilterVarValueGetCardinality(const virNWFilterVarValue *val)
161 {
162 switch (val->valType) {
163 case NWFILTER_VALUE_TYPE_SIMPLE:
164 return 1;
165 case NWFILTER_VALUE_TYPE_ARRAY:
166 return val->u.array.nValues;
167 case NWFILTER_VALUE_TYPE_LAST:
168 return 0;
169 }
170 return 0;
171 }
172
173 bool
virNWFilterVarValueEqual(const virNWFilterVarValue * a,const virNWFilterVarValue * b)174 virNWFilterVarValueEqual(const virNWFilterVarValue *a,
175 const virNWFilterVarValue *b)
176 {
177 unsigned int card;
178 size_t i, j;
179 const char *s;
180
181 if (!a || !b)
182 return false;
183
184 card = virNWFilterVarValueGetCardinality(a);
185 if (card != virNWFilterVarValueGetCardinality(b))
186 return false;
187
188 /* brute force O(n^2) comparison */
189 for (i = 0; i < card; i++) {
190 bool eq = false;
191
192 s = virNWFilterVarValueGetNthValue(a, i);
193 for (j = 0; j < card; j++) {
194 if (STREQ_NULLABLE(s, virNWFilterVarValueGetNthValue(b, j))) {
195 eq = true;
196 break;
197 }
198 }
199 if (!eq)
200 return false;
201 }
202 return true;
203 }
204
205 int
virNWFilterVarValueAddValue(virNWFilterVarValue * val,char * value)206 virNWFilterVarValueAddValue(virNWFilterVarValue *val, char *value)
207 {
208 char *tmp;
209 int rc = -1;
210
211 switch (val->valType) {
212 case NWFILTER_VALUE_TYPE_SIMPLE:
213 /* switch to array */
214 tmp = val->u.simple.value;
215 val->u.array.values = g_new0(char *, 2);
216 val->valType = NWFILTER_VALUE_TYPE_ARRAY;
217 val->u.array.nValues = 2;
218 val->u.array.values[0] = tmp;
219 val->u.array.values[1] = value;
220 rc = 0;
221 break;
222
223 case NWFILTER_VALUE_TYPE_ARRAY:
224 VIR_EXPAND_N(val->u.array.values, val->u.array.nValues, 1);
225 val->u.array.values[val->u.array.nValues - 1] = value;
226 rc = 0;
227 break;
228
229 case NWFILTER_VALUE_TYPE_LAST:
230 break;
231 }
232
233 return rc;
234 }
235
236
237 int
virNWFilterVarValueAddValueCopy(virNWFilterVarValue * val,const char * value)238 virNWFilterVarValueAddValueCopy(virNWFilterVarValue *val, const char *value)
239 {
240 char *valdup;
241 valdup = g_strdup(value);
242 if (virNWFilterVarValueAddValue(val, valdup) < 0) {
243 VIR_FREE(valdup);
244 return -1;
245 }
246 return 0;
247 }
248
249
250 static int
virNWFilterVarValueDelNthValue(virNWFilterVarValue * val,unsigned int pos)251 virNWFilterVarValueDelNthValue(virNWFilterVarValue *val, unsigned int pos)
252 {
253 switch (val->valType) {
254 case NWFILTER_VALUE_TYPE_SIMPLE:
255 return -1;
256
257 case NWFILTER_VALUE_TYPE_ARRAY:
258 if (pos < val->u.array.nValues) {
259 VIR_FREE(val->u.array.values[pos]);
260 VIR_DELETE_ELEMENT(val->u.array.values, pos, val->u.array.nValues);
261 return 0;
262 }
263 break;
264
265 case NWFILTER_VALUE_TYPE_LAST:
266 break;
267 }
268
269 return -1;
270 }
271
272 int
virNWFilterVarValueDelValue(virNWFilterVarValue * val,const char * value)273 virNWFilterVarValueDelValue(virNWFilterVarValue *val, const char *value)
274 {
275 size_t i;
276
277 switch (val->valType) {
278 case NWFILTER_VALUE_TYPE_SIMPLE:
279 return -1;
280
281 case NWFILTER_VALUE_TYPE_ARRAY:
282 for (i = 0; i < val->u.array.nValues; i++)
283 if (STREQ(value, val->u.array.values[i]))
284 return virNWFilterVarValueDelNthValue(val, i);
285 break;
286
287 case NWFILTER_VALUE_TYPE_LAST:
288 break;
289 }
290
291 return -1;
292 }
293
294 void
virNWFilterVarCombIterFree(virNWFilterVarCombIter * ci)295 virNWFilterVarCombIterFree(virNWFilterVarCombIter *ci)
296 {
297 size_t i;
298
299 if (!ci)
300 return;
301
302 for (i = 0; i < ci->nIter; i++)
303 g_free(ci->iter[i].varNames);
304
305 g_free(ci->iter);
306
307 g_free(ci);
308 }
309
310 static int
virNWFilterVarCombIterGetIndexByIterId(virNWFilterVarCombIter * ci,unsigned int iterId)311 virNWFilterVarCombIterGetIndexByIterId(virNWFilterVarCombIter *ci,
312 unsigned int iterId)
313 {
314 size_t i;
315
316 for (i = 0; i < ci->nIter; i++)
317 if (ci->iter[i].iterId == iterId)
318 return i;
319
320 return -1;
321 }
322
323 static void
virNWFilterVarCombIterEntryInit(virNWFilterVarCombIterEntry * cie,unsigned int iterId)324 virNWFilterVarCombIterEntryInit(virNWFilterVarCombIterEntry *cie,
325 unsigned int iterId)
326 {
327 memset(cie, 0, sizeof(*cie));
328 cie->iterId = iterId;
329 }
330
331 static int
virNWFilterVarCombIterAddVariable(virNWFilterVarCombIterEntry * cie,GHashTable * hash,const virNWFilterVarAccess * varAccess)332 virNWFilterVarCombIterAddVariable(virNWFilterVarCombIterEntry *cie,
333 GHashTable *hash,
334 const virNWFilterVarAccess *varAccess)
335 {
336 virNWFilterVarValue *varValue;
337 unsigned int maxValue = 0, minValue = 0;
338 const char *varName = virNWFilterVarAccessGetVarName(varAccess);
339
340 varValue = virHashLookup(hash, varName);
341 if (varValue == NULL) {
342 virReportError(VIR_ERR_INTERNAL_ERROR,
343 _("Could not find value for variable '%s'"),
344 varName);
345 return -1;
346 }
347
348 switch (virNWFilterVarAccessGetType(varAccess)) {
349 case VIR_NWFILTER_VAR_ACCESS_ELEMENT:
350 maxValue = virNWFilterVarAccessGetIndex(varAccess);
351 minValue = maxValue;
352 break;
353 case VIR_NWFILTER_VAR_ACCESS_ITERATOR:
354 maxValue = virNWFilterVarValueGetCardinality(varValue) - 1;
355 minValue = 0;
356 break;
357 case VIR_NWFILTER_VAR_ACCESS_LAST:
358 return -1;
359 }
360
361 if (cie->nVarNames == 0) {
362 cie->maxValue = maxValue;
363 cie->minValue = minValue;
364 cie->curValue = minValue;
365 } else {
366 if (cie->maxValue != maxValue) {
367 virReportError(VIR_ERR_INTERNAL_ERROR,
368 _("Cardinality of list items must be "
369 "the same for processing them in "
370 "parallel"));
371 return -1;
372 }
373 }
374
375 VIR_EXPAND_N(cie->varNames, cie->nVarNames, 1);
376 cie->varNames[cie->nVarNames - 1] = varName;
377
378 return 0;
379 }
380
381 /*
382 * Test whether the iterator entry points to a distinguished set of entries
383 * that have not been seen before at one of the previous iterations.
384 *
385 * The point of this function is to eliminate duplicates.
386 * Example with two lists:
387 *
388 * list1 = [1,2,1]
389 * list2 = [1,3,1]
390 *
391 * The 1st iteration would take the 1st items of each list -> 1,1
392 * The 2nd iteration would take the 2nd items of each list -> 2,3
393 * The 3rd iteration would take the 3rd items of each list -> 1,1 but
394 * skip them since this pair has already been encountered in the 1st iteration
395 */
396 static bool
virNWFilterVarCombIterEntryAreUniqueEntries(virNWFilterVarCombIterEntry * cie,GHashTable * hash)397 virNWFilterVarCombIterEntryAreUniqueEntries(virNWFilterVarCombIterEntry *cie,
398 GHashTable *hash)
399 {
400 size_t i, j;
401 virNWFilterVarValue *varValue;
402 virNWFilterVarValue *tmp;
403 const char *value;
404
405 varValue = virHashLookup(hash, cie->varNames[0]);
406 if (!varValue) {
407 /* caller's error */
408 VIR_ERROR(_("hash lookup resulted in NULL pointer"));
409 return true;
410 }
411
412 value = virNWFilterVarValueGetNthValue(varValue, cie->curValue);
413 if (!value) {
414 VIR_ERROR(_("Lookup of value at index %u resulted in a NULL "
415 "pointer"), cie->curValue);
416 return true;
417 }
418
419 for (i = 0; i < cie->curValue; i++) {
420 if (STREQ(value, virNWFilterVarValueGetNthValue(varValue, i))) {
421 bool isSame = true;
422 for (j = 1; j < cie->nVarNames; j++) {
423 tmp = virHashLookup(hash, cie->varNames[j]);
424 if (!tmp) {
425 /* should never occur to step on a NULL here */
426 return true;
427 }
428 if (STRNEQ(virNWFilterVarValueGetNthValue(tmp, cie->curValue),
429 virNWFilterVarValueGetNthValue(tmp, i))) {
430 isSame = false;
431 break;
432 }
433 }
434 if (isSame)
435 return false;
436 }
437 }
438
439 return true;
440 }
441
442 /*
443 * Create an iterator over the contents of the given variables. All variables
444 * must have entries in the hash table.
445 * The iterator that is created processes all given variables in parallel,
446 * meaning it will access $ITEM1[0] and $ITEM2[0] then $ITEM1[1] and $ITEM2[1]
447 * up to $ITEM1[n] and $ITEM2[n]. For this to work, the cardinality of all
448 * processed lists must be the same.
449 * The notation $ITEM1 and $ITEM2 (in one rule) therefore will always have to
450 * process the items in parallel. This will be an implicit notation for
451 * $ITEM1[@0] and $ITEM2[@0] to 'lock' the two together. Future notations of
452 * $ITEM1[@1] and $ITEM2[@2] will make them be processed independently,
453 * which then would cause all combinations of the items of the two lists to
454 * be created.
455 */
456 virNWFilterVarCombIter *
virNWFilterVarCombIterCreate(GHashTable * hash,virNWFilterVarAccess ** varAccess,size_t nVarAccess)457 virNWFilterVarCombIterCreate(GHashTable *hash,
458 virNWFilterVarAccess **varAccess,
459 size_t nVarAccess)
460 {
461 virNWFilterVarCombIter *res;
462 size_t i;
463 unsigned int iterId;
464 int iterIndex = -1;
465 unsigned int nextIntIterId = VIR_NWFILTER_MAX_ITERID + 1;
466
467 res = g_new0(virNWFilterVarCombIter, 1);
468 res->iter = g_new0(virNWFilterVarCombIterEntry, nVarAccess + 1);
469
470 res->hashTable = hash;
471
472 /* create the default iterator to support @0 */
473 iterId = 0;
474
475 res->nIter = 1;
476 virNWFilterVarCombIterEntryInit(&res->iter[0], iterId);
477
478 for (i = 0; i < nVarAccess; i++) {
479 switch (virNWFilterVarAccessGetType(varAccess[i])) {
480 case VIR_NWFILTER_VAR_ACCESS_ITERATOR:
481 iterId = virNWFilterVarAccessGetIterId(varAccess[i]);
482 iterIndex = virNWFilterVarCombIterGetIndexByIterId(res, iterId);
483 if (iterIndex < 0) {
484 iterIndex = res->nIter;
485 virNWFilterVarCombIterEntryInit(&res->iter[iterIndex], iterId);
486 res->nIter++;
487 }
488 break;
489 case VIR_NWFILTER_VAR_ACCESS_ELEMENT:
490 iterIndex = res->nIter;
491 virNWFilterVarAccessSetIntIterId(varAccess[i], nextIntIterId);
492 virNWFilterVarCombIterEntryInit(&res->iter[iterIndex],
493 nextIntIterId);
494 nextIntIterId++;
495 res->nIter++;
496 break;
497 case VIR_NWFILTER_VAR_ACCESS_LAST:
498 goto err_exit;
499 }
500
501 if (virNWFilterVarCombIterAddVariable(&res->iter[iterIndex],
502 hash, varAccess[i]) < 0)
503 goto err_exit;
504 }
505
506 return res;
507
508 err_exit:
509 virNWFilterVarCombIterFree(res);
510 return NULL;
511 }
512
513 virNWFilterVarCombIter *
virNWFilterVarCombIterNext(virNWFilterVarCombIter * ci)514 virNWFilterVarCombIterNext(virNWFilterVarCombIter *ci)
515 {
516 size_t i;
517
518 for (i = 0; i < ci->nIter; i++) {
519 next:
520 ci->iter[i].curValue++;
521 if (ci->iter[i].curValue <= ci->iter[i].maxValue) {
522 if (!virNWFilterVarCombIterEntryAreUniqueEntries(
523 &ci->iter[i], ci->hashTable))
524 goto next;
525 break;
526 } else {
527 ci->iter[i].curValue = ci->iter[i].minValue;
528 }
529 }
530
531 if (ci->nIter == i)
532 return NULL;
533
534 return ci;
535 }
536
537 const char *
virNWFilterVarCombIterGetVarValue(virNWFilterVarCombIter * ci,const virNWFilterVarAccess * vap)538 virNWFilterVarCombIterGetVarValue(virNWFilterVarCombIter *ci,
539 const virNWFilterVarAccess *vap)
540 {
541 size_t i;
542 unsigned int iterId;
543 bool found = false;
544 const char *res = NULL;
545 virNWFilterVarValue *value;
546 int iterIndex = -1;
547 const char *varName = virNWFilterVarAccessGetVarName(vap);
548
549 switch (virNWFilterVarAccessGetType(vap)) {
550 case VIR_NWFILTER_VAR_ACCESS_ITERATOR:
551 iterId = virNWFilterVarAccessGetIterId(vap);
552 iterIndex = virNWFilterVarCombIterGetIndexByIterId(ci, iterId);
553 if (iterIndex < 0) {
554 virReportError(VIR_ERR_INTERNAL_ERROR,
555 _("Could not get iterator index for "
556 "iterator ID %u"), iterId);
557 return NULL;
558 }
559 break;
560 case VIR_NWFILTER_VAR_ACCESS_ELEMENT:
561 iterId = virNWFilterVarAccessGetIntIterId(vap);
562 iterIndex = virNWFilterVarCombIterGetIndexByIterId(ci, iterId);
563 if (iterIndex < 0) {
564 virReportError(VIR_ERR_INTERNAL_ERROR,
565 _("Could not get iterator index for "
566 "(internal) iterator ID %u"), iterId);
567 return NULL;
568 }
569 break;
570 case VIR_NWFILTER_VAR_ACCESS_LAST:
571 return NULL;
572 }
573
574 for (i = 0; i < ci->iter[iterIndex].nVarNames; i++) {
575 if (STREQ(ci->iter[iterIndex].varNames[i], varName)) {
576 found = true;
577 break;
578 }
579 }
580
581 if (!found) {
582 virReportError(VIR_ERR_INTERNAL_ERROR,
583 _("Could not find variable '%s' in iterator"),
584 varName);
585 return NULL;
586 }
587
588 value = virHashLookup(ci->hashTable, varName);
589 if (!value) {
590 virReportError(VIR_ERR_INTERNAL_ERROR,
591 _("Could not find value for variable '%s'"),
592 varName);
593 return NULL;
594 }
595
596 res = virNWFilterVarValueGetNthValue(value, ci->iter[iterIndex].curValue);
597 if (!res) {
598 virReportError(VIR_ERR_INTERNAL_ERROR,
599 _("Could not get nth (%u) value of "
600 "variable '%s'"),
601 ci->iter[iterIndex].curValue, varName);
602 return NULL;
603 }
604
605 return res;
606 }
607
608 void
virNWFilterVarValueHashFree(void * payload)609 virNWFilterVarValueHashFree(void *payload)
610 {
611 virNWFilterVarValueFree(payload);
612 }
613
614
615 struct addToTableStruct {
616 GHashTable *target;
617 int errOccurred;
618 };
619
620
621 static int
addToTable(void * payload,const char * name,void * data)622 addToTable(void *payload, const char *name, void *data)
623 {
624 struct addToTableStruct *atts = (struct addToTableStruct *)data;
625 virNWFilterVarValue *val;
626
627 if (atts->errOccurred)
628 return 0;
629
630 val = virNWFilterVarValueCopy((virNWFilterVarValue *)payload);
631 if (!val) {
632 atts->errOccurred = 1;
633 return 0;
634 }
635
636 if (virHashUpdateEntry(atts->target, (const char *)name, val) < 0) {
637 atts->errOccurred = 1;
638 virNWFilterVarValueFree(val);
639 }
640
641 return 0;
642 }
643
644
645 int
virNWFilterHashTablePutAll(GHashTable * src,GHashTable * dest)646 virNWFilterHashTablePutAll(GHashTable *src,
647 GHashTable *dest)
648 {
649 struct addToTableStruct atts = {
650 .target = dest,
651 .errOccurred = 0,
652 };
653
654 virHashForEach(src, addToTable, &atts);
655 if (atts.errOccurred)
656 return -1;
657
658 return 0;
659 }
660
661 /* The general purpose function virNWFilterVarValueEqual returns a
662 * bool, but the comparison callback for virHashEqual (called below)
663 * needs to return an int of 0 for == and non-0 for !=
664 */
665 static int
virNWFilterVarValueCompare(const void * a,const void * b)666 virNWFilterVarValueCompare(const void *a, const void *b)
667 {
668 return virNWFilterVarValueEqual((const virNWFilterVarValue *) a,
669 (const virNWFilterVarValue *) b) ? 0 : 1;
670 }
671
672 bool
virNWFilterHashTableEqual(GHashTable * a,GHashTable * b)673 virNWFilterHashTableEqual(GHashTable *a,
674 GHashTable *b)
675 {
676 return virHashEqual(a, b, virNWFilterVarValueCompare);
677 }
678
679 static bool
isValidVarName(const char * var)680 isValidVarName(const char *var)
681 {
682 return var[strspn(var, VALID_VARNAME)] == 0;
683 }
684
685
686 static bool
isValidVarValue(const char * value)687 isValidVarValue(const char *value)
688 {
689 return (value[strspn(value, VALID_VARVALUE)] == 0) && (strlen(value) != 0);
690 }
691
692 static virNWFilterVarValue *
virNWFilterParseVarValue(const char * val)693 virNWFilterParseVarValue(const char *val)
694 {
695 return virNWFilterVarValueCreateSimpleCopyValue(val);
696 }
697
698 GHashTable *
virNWFilterParseParamAttributes(xmlNodePtr cur)699 virNWFilterParseParamAttributes(xmlNodePtr cur)
700 {
701 g_autoptr(GHashTable) table = virHashNew(virNWFilterVarValueHashFree);
702
703 for (cur = xmlFirstElementChild(cur); cur != NULL;
704 cur = xmlNextElementSibling(cur)) {
705 if (virXMLNodeNameEqual(cur, "parameter")) {
706 g_autofree char *nam = virXMLPropString(cur, "name");
707 g_autofree char *val = virXMLPropString(cur, "value");
708 g_autoptr(virNWFilterVarValue) value = NULL;
709
710 if (nam == NULL || !isValidVarName(nam) ||
711 val == NULL || !isValidVarValue(val)) {
712 continue;
713 }
714
715 if ((value = virHashLookup(table, nam))) {
716 /* add value to existing value -> list */
717 if (virNWFilterVarValueAddValue(g_steal_pointer(&value), val) < 0)
718 return NULL;
719 val = NULL;
720 } else if ((value = virNWFilterParseVarValue(val))) {
721 if (virHashUpdateEntry(table, nam, value) < 0)
722 return NULL;
723 }
724 value = NULL;
725 }
726 }
727
728 return g_steal_pointer(&table);
729 }
730
731
732 int
virNWFilterFormatParamAttributes(virBuffer * buf,GHashTable * table,const char * filterref)733 virNWFilterFormatParamAttributes(virBuffer *buf,
734 GHashTable *table,
735 const char *filterref)
736 {
737 virHashKeyValuePair *items;
738 size_t i, j;
739 int card, numKeys;
740
741 numKeys = virHashSize(table);
742
743 if (numKeys < 0) {
744 virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
745 _("missing filter parameter table"));
746 return -1;
747 }
748
749 items = virHashGetItems(table, NULL, true);
750 if (!items)
751 return -1;
752
753 virBufferAsprintf(buf, "<filterref filter='%s'", filterref);
754 if (numKeys) {
755 virBufferAddLit(buf, ">\n");
756 virBufferAdjustIndent(buf, 2);
757 for (i = 0; i < numKeys; i++) {
758 const virNWFilterVarValue *value = items[i].value;
759
760 card = virNWFilterVarValueGetCardinality(value);
761
762 for (j = 0; j < card; j++)
763 virBufferAsprintf(buf,
764 "<parameter name='%s' value='%s'/>\n",
765 (const char *)items[i].key,
766 virNWFilterVarValueGetNthValue(value, j));
767
768 }
769 virBufferAdjustIndent(buf, -2);
770 virBufferAddLit(buf, "</filterref>\n");
771 } else {
772 virBufferAddLit(buf, "/>\n");
773 }
774
775 VIR_FREE(items);
776
777 return 0;
778 }
779
780 void
virNWFilterVarAccessFree(virNWFilterVarAccess * varAccess)781 virNWFilterVarAccessFree(virNWFilterVarAccess *varAccess)
782 {
783 if (!varAccess)
784 return;
785
786 g_free(varAccess->varName);
787 g_free(varAccess);
788 }
789
790 bool
virNWFilterVarAccessEqual(const virNWFilterVarAccess * a,const virNWFilterVarAccess * b)791 virNWFilterVarAccessEqual(const virNWFilterVarAccess *a,
792 const virNWFilterVarAccess *b)
793 {
794 if (a->accessType != b->accessType)
795 return false;
796
797 if (STRNEQ(a->varName, b->varName))
798 return false;
799
800 switch (a->accessType) {
801 case VIR_NWFILTER_VAR_ACCESS_ELEMENT:
802 return (a->u.index.idx == b->u.index.idx &&
803 a->u.index.intIterId == b->u.index.intIterId);
804 case VIR_NWFILTER_VAR_ACCESS_ITERATOR:
805 return a->u.iterId == b->u.iterId;
806 case VIR_NWFILTER_VAR_ACCESS_LAST:
807 break;
808 }
809 return false;
810 }
811
812 /*
813 * Parse a variable access like
814 * IP, IP[@2], IP[3]
815 */
816 virNWFilterVarAccess *
virNWFilterVarAccessParse(const char * varAccess)817 virNWFilterVarAccessParse(const char *varAccess)
818 {
819 size_t idx, varNameLen;
820 virNWFilterVarAccess *dest;
821 const char *input = varAccess;
822
823 dest = g_new0(virNWFilterVarAccess, 1);
824
825 idx = strspn(input, VALID_VARNAME);
826
827 if (input[idx] == '\0') {
828 /* in the form 'IP', which is equivalent to IP[@0] */
829 dest->varName = g_strndup(input, idx);
830 dest->accessType = VIR_NWFILTER_VAR_ACCESS_ITERATOR;
831 dest->u.iterId = 0;
832 return dest;
833 }
834
835 if (input[idx] == '[') {
836 char *end_ptr;
837 unsigned int result;
838 bool parseError = false;
839
840 varNameLen = idx;
841
842 dest->varName = g_strndup(input, varNameLen);
843
844 input += idx + 1;
845 virSkipSpaces(&input);
846
847 if (*input == '@') {
848 /* in the form 'IP[@<number>] -> iterator */
849 dest->accessType = VIR_NWFILTER_VAR_ACCESS_ITERATOR;
850 input++;
851 } else {
852 /* in the form 'IP[<number>] -> element */
853 dest->accessType = VIR_NWFILTER_VAR_ACCESS_ELEMENT;
854 }
855
856 if (virStrToLong_ui(input, &end_ptr, 10, &result) < 0)
857 parseError = true;
858 if (!parseError) {
859 input = end_ptr;
860 virSkipSpaces(&input);
861 if (*input != ']')
862 parseError = true;
863 }
864 if (parseError) {
865 if (dest->accessType == VIR_NWFILTER_VAR_ACCESS_ELEMENT)
866 virReportError(VIR_ERR_INVALID_ARG, "%s",
867 _("Malformatted array index"));
868 else
869 virReportError(VIR_ERR_INVALID_ARG, "%s",
870 _("Malformatted iterator id"));
871 goto err_exit;
872 }
873
874 switch (dest->accessType) {
875 case VIR_NWFILTER_VAR_ACCESS_ELEMENT:
876 dest->u.index.idx = result;
877 dest->u.index.intIterId = ~0;
878 break;
879 case VIR_NWFILTER_VAR_ACCESS_ITERATOR:
880 if (result > VIR_NWFILTER_MAX_ITERID) {
881 virReportError(VIR_ERR_INVALID_ARG,
882 _("Iterator ID exceeds maximum ID "
883 "of %u"), VIR_NWFILTER_MAX_ITERID);
884 goto err_exit;
885 }
886 dest->u.iterId = result;
887 break;
888 case VIR_NWFILTER_VAR_ACCESS_LAST:
889 goto err_exit;
890 }
891
892 return dest;
893 } else {
894 virReportError(VIR_ERR_INVALID_ARG, "%s",
895 _("Malformatted variable"));
896 }
897
898 err_exit:
899 virNWFilterVarAccessFree(dest);
900
901 return NULL;
902 }
903
904 void
virNWFilterVarAccessPrint(virNWFilterVarAccess * vap,virBuffer * buf)905 virNWFilterVarAccessPrint(virNWFilterVarAccess *vap, virBuffer *buf)
906 {
907 virBufferAdd(buf, vap->varName, -1);
908 switch (vap->accessType) {
909 case VIR_NWFILTER_VAR_ACCESS_ELEMENT:
910 virBufferAsprintf(buf, "[%u]", vap->u.index.idx);
911 break;
912 case VIR_NWFILTER_VAR_ACCESS_ITERATOR:
913 if (vap->u.iterId != 0)
914 virBufferAsprintf(buf, "[@%u]", vap->u.iterId);
915 break;
916 case VIR_NWFILTER_VAR_ACCESS_LAST:
917 break;
918 }
919 }
920
921 const char *
virNWFilterVarAccessGetVarName(const virNWFilterVarAccess * vap)922 virNWFilterVarAccessGetVarName(const virNWFilterVarAccess *vap)
923 {
924 return vap->varName;
925 }
926
927 virNWFilterVarAccessType
virNWFilterVarAccessGetType(const virNWFilterVarAccess * vap)928 virNWFilterVarAccessGetType(const virNWFilterVarAccess *vap)
929 {
930 return vap->accessType;
931 }
932
933 unsigned int
virNWFilterVarAccessGetIterId(const virNWFilterVarAccess * vap)934 virNWFilterVarAccessGetIterId(const virNWFilterVarAccess *vap)
935 {
936 return vap->u.iterId;
937 }
938
939 unsigned int
virNWFilterVarAccessGetIndex(const virNWFilterVarAccess * vap)940 virNWFilterVarAccessGetIndex(const virNWFilterVarAccess *vap)
941 {
942 return vap->u.index.idx;
943 }
944
945 static void
virNWFilterVarAccessSetIntIterId(virNWFilterVarAccess * vap,unsigned int intIterId)946 virNWFilterVarAccessSetIntIterId(virNWFilterVarAccess *vap,
947 unsigned int intIterId)
948 {
949 vap->u.index.intIterId = intIterId;
950 }
951
952 static unsigned int
virNWFilterVarAccessGetIntIterId(const virNWFilterVarAccess * vap)953 virNWFilterVarAccessGetIntIterId(const virNWFilterVarAccess *vap)
954 {
955 return vap->u.index.intIterId;
956 }
957
958 bool
virNWFilterVarAccessIsAvailable(const virNWFilterVarAccess * varAccess,GHashTable * hash)959 virNWFilterVarAccessIsAvailable(const virNWFilterVarAccess *varAccess,
960 GHashTable *hash)
961 {
962 const char *varName = virNWFilterVarAccessGetVarName(varAccess);
963 const char *res;
964 unsigned int idx;
965 virNWFilterVarValue *varValue;
966
967 varValue = virHashLookup(hash, varName);
968 if (!varValue)
969 return false;
970
971 switch (virNWFilterVarAccessGetType(varAccess)) {
972 case VIR_NWFILTER_VAR_ACCESS_ELEMENT:
973 idx = virNWFilterVarAccessGetIndex(varAccess);
974 res = virNWFilterVarValueGetNthValue(varValue, idx);
975 if (res == NULL)
976 return false;
977 break;
978 case VIR_NWFILTER_VAR_ACCESS_ITERATOR:
979 break;
980 case VIR_NWFILTER_VAR_ACCESS_LAST:
981 return false;
982 }
983
984 return true;
985 }
986