2 * Copyright (C) 1999 WIDE Project.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. Neither the name of the project nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE PROJECT AND CONTRIBUTORS ``AS IS'' AND
18 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20 * ARE DISCLAIMED. IN NO EVENT SHALL THE PROJECT 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
23 * OR 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
32 #include <sys/types.h>
34 #include <netinet/in.h>
36 #include <arpa/inet.h>
53 #define set_param(var,val,p) \
56 yywarn("%s doubly defined(ignore %d)", (p), (val));\
64 struct in6_addr paddr;
69 struct attr_list *next;
74 struct in6_prefix prefix;
78 enum {IFA_FLAG, IFA_PREFERENCE, IFA_METRIC, RPA_PRIORITY, RPA_TIME,
79 BSRA_PRIORITY, BSRA_TIME, BSRA_MASKLEN, IN6_PREFIX, THRESA_RATE,
82 static int strict; /* flag if the grammer check is strict */
83 static struct attr_list *rp_attr, *bsr_attr, *grp_prefix, *regthres_attr,
85 static char *cand_rp_ifname, *cand_bsr_ifname;
86 static int srcmetric, srcpref, helloperiod, jpperiod, granularity,
87 datatimo, regsuptimo, probetime, asserttimo;
88 static double helloperiod_coef, jpperiod_coef;
92 extern int yylex __P((void));
99 struct attr_list *attr;
103 %token LOGGING LOGLEV NOLOGLEV
106 %token PHYINT IFNAME DISABLE PREFERENCE METRIC NOLISTENER
108 %token CANDRP CANDBSR TIME PRIORITY MASKLEN
109 %token NUMBER STRING SLASH
110 %token REGTHRES DATATHRES RATE INTERVAL
111 %token SRCMETRIC SRCPREF HELLOPERIOD GRANULARITY JPPERIOD
112 %token DATATIME REGSUPTIME PROBETIME ASSERTTIME
114 %type <num> LOGLEV NOLOGLEV
116 %type <val> STRING IFNAME
117 %type <attr> if_attributes rp_substatement rp_attributes
118 %type <attr> bsr_substatement bsr_attributes thres_attributes
123 | statements statement
128 | reverselookup_statement
134 | datathres_statement
140 LOGGING log_specs EOS
145 | log_specs LOGLEV {debug |= $2;}
146 | log_specs NOLOGLEV {debug &= ~($2);}
150 reverselookup_statement:
151 REVERSELOOKUP YES EOS { numerichost = FALSE; }
152 | REVERSELOOKUP NO EOS { numerichost = TRUE; }
157 PHYINT IFNAME if_attributes EOS {
161 free($2.v); /* XXX */
163 yywarn("unknown interface: %s", $2.v);
171 for (p = (struct attr_list *)v->config_attr;
172 p && p->next; p = p->next)
175 p->next = (void *)$3;
177 v->config_attr = (void *)$3;
184 | if_attributes DISABLE
186 if (($$ = add_attribute_flag($1, IFA_FLAG,
187 VIFF_DISABLED)) == NULL)
190 | if_attributes NOLISTENER
192 if (($$ = add_attribute_flag($1, IFA_FLAG,
193 VIFF_NOLISTENER)) == NULL)
196 | if_attributes PREFERENCE NUMBER
198 if (($$ = add_attribute_num($1, IFA_PREFERENCE, $3))
202 | if_attributes METRIC NUMBER
204 if (($$ = add_attribute_num($1, IFA_METRIC, $3))
212 CANDRP rp_substatement EOS {
213 if (cand_rp_flag == TRUE) {
214 yywarn("cand_rp doubly defined");
225 /* XXX: intermediate rule to avoid shift-reduce conflict */
229 if (cand_rp_ifname) {
230 yywarn("ifname for cand_rp doubly defined");
235 cand_rp_ifname = $1.v;
242 | rp_attributes PRIORITY NUMBER
244 if (($$ = add_attribute_num($1, RPA_PRIORITY, $3))
248 | rp_attributes TIME NUMBER
250 if (($$ = add_attribute_num($1, RPA_TIME, $3))
256 /* cand_bootstrap_router */
258 CANDBSR bsr_substatement EOS {
259 if (cand_bsr_flag == TRUE) {
260 yywarn("cand_bsr doubly defined");
266 cand_bsr_flag = TRUE;
271 /* XXX: intermediate rule to avoid shift-reduce conflict */
273 IFNAME bsr_attributes
275 if (cand_bsr_ifname) {
276 yywarn("ifname for cand_bsr doubly defined");
281 cand_bsr_ifname = $1.v;
289 | bsr_attributes PRIORITY NUMBER
291 if (($$ = add_attribute_num($1, BSRA_PRIORITY, $3))
295 | bsr_attributes TIME NUMBER
297 if (($$ = add_attribute_num($1, BSRA_TIME, $3))
301 | bsr_attributes MASKLEN NUMBER
305 if (masklen < 0 || masklen > 128)
306 yywarn("invalid mask length: %d (ignored)",
308 else if (($$ = add_attribute_num($1, BSRA_MASKLEN,
315 /* group_prefix <group-addr>/<prefix_len> */
317 GRPPFX STRING SLASH NUMBER EOS {
318 struct in6_prefix prefix;
321 if (inet_pton(AF_INET6, $2.v, &prefix.paddr) != 1) {
322 yywarn("invalid IPv6 address: %s (ignored)", $2);
325 free($2.v); /* XXX: which was allocated dynamically */
328 if (prefix.plen < 0 || prefix.plen > 128) {
329 yywarn("invalid prefix length: %d (ignored)",
333 if (IN6_IS_ADDR_MC_NODELOCAL(&prefix.paddr) ||
334 IN6_IS_ADDR_MC_LINKLOCAL(&prefix.paddr)) {
335 yywarn("group prefix (%s/%d) has a narrow scope "
337 inet6_fmt(&prefix.paddr), prefix.plen);
342 struct attr_list *new;
344 if ((new = malloc(sizeof(*new))) == NULL) {
345 yyerror("malloc failed");
348 memset(new, 0, sizeof(*new));
350 new->type = IN6_PREFIX;
351 new->attru.prefix = prefix;
352 new->next = grp_prefix;
360 * switch_register_threshold [rate <number> interval <number>]
361 * Operation: reads and assigns the switch to the spt threshold
362 * due to registers for the router, if used as RP.
363 * Maybe extended to support different thresholds for different
367 REGTHRES thres_attributes EOS {
369 yywarn("switch_register_threshold doubly defined");
381 | thres_attributes RATE NUMBER
383 if (($$ = add_attribute_num($1, THRESA_RATE, $3))
387 | thres_attributes INTERVAL NUMBER
389 if (($$ = add_attribute_num($1, THRESA_INTERVAL, $3))
395 * switch_data_threshold [rate <number> interval <number>]
396 * Operation: reads and assigns the switch to the spt threshold due to
397 * data packets, if used as DR.
400 DATATHRES thres_attributes EOS {
401 if (datathres_attr) {
402 yywarn("switch_data_threshold doubly defined");
415 set_param(srcmetric, $2, "default_source_metric");
419 set_param(srcpref, $2, "default_source_preference");
421 | HELLOPERIOD NUMBER EOS
423 set_param(helloperiod, $2, "hello_period");
425 | HELLOPERIOD NUMBER NUMBER EOS
427 set_param(helloperiod, $2, "hello_period");
428 set_param(helloperiod_coef, $3, "hello_period(coef)");
430 | JPPERIOD NUMBER EOS
432 set_param(jpperiod, $2, "join_prune_period");
434 | JPPERIOD NUMBER NUMBER EOS
436 set_param(jpperiod, $2, "join_prune_period");
437 set_param(jpperiod_coef, $3, "join_prune_period(coef)");
439 | GRANULARITY NUMBER EOS
441 set_param(granularity, $2, "granularity");
443 | DATATIME NUMBER EOS
445 set_param(datatimo, $2, "data_timeout");
447 | REGSUPTIME NUMBER EOS
449 set_param(regsuptimo, $2, "register_suppression_timeout");
451 | PROBETIME NUMBER EOS
453 set_param(probetime, $2, "probe_time");
455 | ASSERTTIME NUMBER EOS
457 set_param(asserttimo, $2, "assert_timeout");
462 static struct attr_list *add_attribute_flag __P((struct attr_list *, int,
464 static struct attr_list *add_attribute_num __P((struct attr_list *, int,
466 static void free_attr_list __P((struct attr_list *));
467 static int param_config __P((void));
468 static int phyint_config __P((void));
469 static int rp_config __P((void));
470 static int bsr_config __P((void));
471 static int grp_prefix_config __P((void));
472 static int regthres_config __P((void));
473 static int datathres_config __P((void));
475 static struct attr_list *
476 add_attribute_flag(list, type, flag)
477 struct attr_list *list;
483 if ((p = malloc(sizeof(*p))) == NULL) {
484 yyerror("malloc failed");
487 memset((void *)p, 0, sizeof(*p));
489 p->attru.flags = flag;
495 /* XXX: too many dup code... */
496 static struct attr_list *
497 add_attribute_num(list, type, num)
498 struct attr_list *list;
504 if ((p = malloc(sizeof(*p))) == NULL) {
505 yyerror("malloc failed");
508 memset((void *)p, 0, sizeof(*p));
510 p->attru.number = num;
518 struct attr_list *list;
520 struct attr_list *p, *next;
522 for(p = list; p; p = next) {
534 /* at first, set the default values to all the undefined variables */
535 if (srcmetric == -1) srcmetric = DEFAULT_LOCAL_METRIC;
536 if (srcpref == -1) srcpref = DEFAULT_LOCAL_PREF;
537 if (helloperiod == -1) helloperiod = PIM_TIMER_HELLO_PERIOD;
538 if (helloperiod_coef == -1) helloperiod_coef = 3.5;
539 if (jpperiod == -1) jpperiod = PIM_JOIN_PRUNE_PERIOD;
540 if (jpperiod_coef == -1) jpperiod_coef = 3.5;
541 if (granularity == -1) granularity = DEFAULT_TIMER_INTERVAL;
542 if (datatimo == -1) datatimo = PIM_DATA_TIMEOUT;
543 if (regsuptimo == -1) regsuptimo = PIM_REGISTER_SUPPRESSION_TIMEOUT;
544 if (probetime == -1) probetime = PIM_REGISTER_PROBE_TIME;
545 if (asserttimo == -1) asserttimo = PIM_ASSERT_TIMEOUT;
547 /* set protocol parameters using the configuration variables */
548 for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v) {
549 v->uv_local_metric = srcmetric;
550 v->uv_local_pref = srcpref;
552 pim_hello_period = helloperiod;
553 pim_hello_holdtime = helloperiod * helloperiod_coef;
554 pim_join_prune_period = jpperiod;
555 pim_join_prune_holdtime = jpperiod * jpperiod_coef;
556 timer_interval = granularity;
557 pim_data_timeout = datatimo;
558 pim_register_suppression_timeout = regsuptimo;
559 pim_register_probe_time = probetime;
560 pim_assert_timeout = asserttimo;
562 IF_DEBUG(DEBUG_PIM_HELLO) {
563 log(LOG_DEBUG, 0, "pim_hello_period set to: %u",
565 log(LOG_DEBUG, 0, "pim_hello_holdtime set to: %u",
569 IF_DEBUG(DEBUG_PIM_JOIN_PRUNE) {
570 log(LOG_DEBUG,0 , "pim_join_prune_period set to: %u",
571 pim_join_prune_period);
572 log(LOG_DEBUG, 0, "pim_join_prune_holdtime set to: %u",
573 pim_join_prune_holdtime);
575 IF_DEBUG(DEBUG_TIMER) {
576 log(LOG_DEBUG,0 , "timer interval set to: %u", timer_interval);
578 IF_DEBUG(DEBUG_PIM_TIMER) {
579 log(LOG_DEBUG,0 , "PIM data timeout set to: %u",
582 IF_DEBUG(DEBUG_PIM_REGISTER) {
584 "PIM register suppression timeout set to: %u",
585 pim_register_suppression_timeout);
586 log(LOG_DEBUG, 0, "PIM register probe time set to: %u",
587 pim_register_probe_time);
589 IF_DEBUG(DEBUG_PIM_ASSERT) {
591 "PIM assert timeout set to: %u",
602 struct attr_list *al;
604 for (vifi = 0, v = uvifs; vifi < numvifs ; ++vifi , ++v) {
605 for (al = (struct attr_list *)v->config_attr; al; al = al->next) {
608 v->uv_flags |= al->attru.flags;
611 if (al->attru.number < 1 ||
612 al->attru.number > 255)
613 yywarn("invalid phyint preference(%d)",
614 (int)al->attru.number);
616 v->uv_local_pref = al->attru.number;
617 IF_DEBUG(DEBUG_ASSERT)
619 "default localpref for %s "
626 if (al->attru.number < 1 ||
627 al->attru.number > 1024)
628 yywarn("invalid metric(%d)",
631 v->uv_metric = al->attru.number;
632 IF_DEBUG(DEBUG_ASSERT)
634 "default local metric for %s "
650 struct sockaddr_in6 *sa6_rp = NULL;
651 struct attr_list *al;
654 /* initialization by default values */
655 my_cand_rp_adv_period = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
656 my_cand_rp_priority = PIM_DEFAULT_CAND_RP_PRIORITY;
658 if (cand_rp_ifname) {
659 sa6_rp = local_iface(cand_rp_ifname);
662 "cand_rp '%s' is not configured. "
663 "take the max local address the router..",
667 for (al = rp_attr; al; al = al->next) {
670 if (al->attru.number < 0)
671 my_cand_rp_priority =
672 PIM_DEFAULT_CAND_RP_PRIORITY;
674 my_cand_rp_priority = al->attru.number;
677 if (al->attru.number < 10)
678 my_cand_rp_adv_period = 10;
679 else if (al->attru.number > PIM_DEFAULT_CAND_RP_ADV_PERIOD)
680 my_cand_rp_adv_period =
681 PIM_DEFAULT_CAND_RP_ADV_PERIOD;
683 my_cand_rp_adv_period = al->attru.number;
686 yywarn("unknown attribute(%d) for RP", al->type);
692 sa6_rp = max_global_address(); /* this MUST suceed */
693 my_cand_rp_address = *sa6_rp;
696 * initialize related parameters
700 * Note that sizeof(pim6_enocd_uni_addr_t) might be larger than
701 * the length of the Encoded-Unicast-address field(18 byte) due to
702 * some padding put in the compiler. However, it doesn't matter
703 * since we use the space just as a buffer(i.e not as the message).
705 cand_rp_adv_message.buffer = (u_int8 *)malloc(4 +
706 sizeof(pim6_encod_uni_addr_t) +
707 255*sizeof(pim6_encod_grp_addr_t));
708 if(cand_rp_adv_message.buffer == NULL)
709 log(LOG_ERR, 0, "Candrpadv Buffer allocation");
711 cand_rp_adv_message.prefix_cnt_ptr = cand_rp_adv_message.buffer;
714 * By default, if no group_prefix configured, then prefix_cnt == 0
715 * implies group_prefix = ff00::/8 and masklen = 8.
717 *cand_rp_adv_message.prefix_cnt_ptr = 0;
718 cand_rp_adv_message.insert_data_ptr = cand_rp_adv_message.buffer;
720 /* TODO: XXX: HARDCODING!!! */
721 cand_rp_adv_message.insert_data_ptr += (4 + 18);
722 cand_rp_adv_message.message_size =
723 cand_rp_adv_message.insert_data_ptr - cand_rp_adv_message.buffer;
725 my_cand_rp_holdtime = 2.5 * my_cand_rp_adv_period;
727 /* TODO: HARDCODING! */
728 data_ptr = cand_rp_adv_message.buffer + 1; /* WARNING */
729 PUT_BYTE(my_cand_rp_priority,data_ptr);
730 PUT_HOSTSHORT(my_cand_rp_holdtime, data_ptr);
731 PUT_EUADDR6(my_cand_rp_address.sin6_addr,data_ptr);
732 IF_DEBUG(DEBUG_PIM_CAND_RP) {
734 "Local Cand-RP address is : %s",
735 inet6_fmt(&my_cand_rp_address.sin6_addr));
737 "Local Cand-RP priority is : %u",my_cand_rp_priority);
739 "Local Cand-RP advertisement period is : %u sec.",
740 my_cand_rp_adv_period);
749 struct sockaddr_in6 *sa6_bsr = NULL;
750 struct attr_list *al;
751 int my_bsr_hash_masklen;
753 /* initialization by default values */
754 my_bsr_period = PIM_DEFAULT_BOOTSTRAP_PERIOD;
755 my_bsr_priority = PIM_DEFAULT_BSR_PRIORITY;
756 my_bsr_hash_masklen = RP_DEFAULT_IPV6_HASHMASKLEN;
758 if (cand_bsr_ifname) {
759 sa6_bsr = local_iface(cand_bsr_ifname);
762 "bsr '%s' is not configured. "
763 "take the max local address the router..",
767 for (al = bsr_attr; al; al = al->next) {
770 if (al->attru.number >= 0)
771 my_bsr_priority = al->attru.number;
774 /* validation has been done. */
775 my_bsr_hash_masklen = al->attru.number;
778 if (al->attru.number < 10)
780 else if (al->attru.number > PIM_DEFAULT_BOOTSTRAP_PERIOD)
782 PIM_DEFAULT_BOOTSTRAP_PERIOD;
784 my_bsr_period = al->attru.number;
787 yywarn("unknown attribute(%d) for BSR", al->type);
793 sa6_bsr = max_global_address(); /* this MUST suceed */
794 my_bsr_address = *sa6_bsr;
795 MASKLEN_TO_MASK6(my_bsr_hash_masklen, my_bsr_hash_mask);
797 IF_DEBUG(DEBUG_PIM_BOOTSTRAP) {
798 log(LOG_DEBUG, 0, "Local BSR address: %s",
799 inet6_fmt(&my_bsr_address.sin6_addr));
800 log(LOG_DEBUG, 0, "Local BSR priority : %u", my_bsr_priority);
801 log(LOG_DEBUG, 0, "Local BSR period is : %u sec.",
803 log(LOG_DEBUG, 0, "Local BSR hash mask length: %d",
804 my_bsr_hash_masklen);
813 struct attr_list *pl;
815 if (cand_rp_flag != TRUE) {
817 "group_prefix was specified without cand_rp(ignored)");
821 for (pl = grp_prefix; pl; pl = pl->next) {
822 if (!IN6_IS_ADDR_MULTICAST(&pl->attru.prefix.paddr)) {
824 "Config error: %s is not a mulicast address(ignored)",
825 inet6_fmt(&pl->attru.prefix.paddr));
829 if (!(~(*cand_rp_adv_message.prefix_cnt_ptr))) {
831 "Too many group_prefix configured. Truncating...");
835 /* validation for plen has almost done */
836 if (pl->attru.prefix.plen < PIM_GROUP_PREFIX_DEFAULT_MASKLEN)
837 pl->attru.prefix.plen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
839 PUT_EGADDR6(pl->attru.prefix.paddr,
840 (u_int8)pl->attru.prefix.plen, 0,
841 cand_rp_adv_message.insert_data_ptr);
842 (*cand_rp_adv_message.prefix_cnt_ptr)++;
845 /* finally, adjust the data size */
846 cand_rp_adv_message.message_size =
847 cand_rp_adv_message.insert_data_ptr - cand_rp_adv_message.buffer;
855 struct attr_list *al;
859 if (cand_rp_flag != TRUE) {
861 "register_threshold was specified without cand_rp");
864 for (al = regthres_attr; al; al = al->next) {
867 if (al->attru.number < 0)
868 yywarn("invalid regthres rate: %d(ignored)",
871 yywarn("regthres rate is doubly defined(ignored)");
873 rate = al->attru.number;
875 case THRESA_INTERVAL:
876 if (al->attru.number < 0)
877 yywarn("invalid regthres interval: %d(ignored)",
879 else if (interval != -1)
880 yywarn("regthres interval is doubly defined(ignored)");
882 interval = al->attru.number;
885 yywarn("unknown attribute(%d) for regthres", al->type);
890 /* set default values if not specified */
892 rate = PIM_DEFAULT_REG_RATE;
894 interval = PIM_DEFAULT_REG_RATE_INTERVAL;
896 pim_reg_rate_bytes = (rate * interval ) /10;
897 pim_reg_rate_check_interval = interval;
905 struct attr_list *al;
909 for (al = datathres_attr; al; al = al->next) {
912 if (al->attru.number < 0)
913 yywarn("invalid datathres rate: %d(ignored)",
916 yywarn("datathres rate is doubly defined(ignored)");
918 rate = al->attru.number;
920 case THRESA_INTERVAL:
921 if (al->attru.number < 0)
922 yywarn("invalid datathres interval: %d(ignored)",
924 else if (interval != -1)
925 yywarn("datathres interval is doubly defined(ignored)");
927 interval = al->attru.number;
930 yywarn("unknown attribute(%d) for datathres", al->type);
935 /* set default values if not specified */
937 rate = PIM_DEFAULT_DATA_RATE;
939 interval = PIM_DEFAULT_DATA_RATE_INTERVAL;
941 pim_data_rate_bytes = (rate * interval ) /10;
942 pim_data_rate_check_interval = interval;
956 param_config(); /* must be called before phyint_conifg() */
960 if (cand_bsr_flag == TRUE)
963 if (cand_rp_flag == TRUE)
966 if (grp_prefix) /* this must be called after rp_config() */
969 if (cand_rp_flag == TRUE)
974 IF_DEBUG(DEBUG_SWITCH) {
975 log(LOG_DEBUG, 0, "reg_rate_limit set to %u (bits/s)",
977 log(LOG_DEBUG, 0, "reg_rate_interval set to %u s.",
978 pim_reg_rate_check_interval);
979 log(LOG_DEBUG, 0, "data_rate_limit set to %u (bits/s)",
980 pim_data_rate_bytes);
981 log(LOG_DEBUG, 0, "data_rate_interval set to %u s.",
982 pim_data_rate_check_interval);
986 /* cleanup temporary variables */
987 if (cand_rp_ifname) free(cand_rp_ifname);
988 if (cand_bsr_ifname) free(cand_bsr_ifname);
989 if (rp_attr) free_attr_list(rp_attr);
990 if (bsr_attr) free_attr_list(bsr_attr);
991 if (grp_prefix) free_attr_list(grp_prefix);
992 if (regthres_attr) free_attr_list(regthres_attr);
993 if (datathres_attr) free_attr_list(datathres_attr);
994 for (vifi = 0, v = uvifs; vifi < numvifs ; ++vifi , ++v)
995 free_attr_list((struct attr_list *)v->config_attr);
1000 /* initialize all the temporary variables */
1012 rp_attr = bsr_attr = grp_prefix = regthres_attr = datathres_attr = NULL;
1014 cand_rp_ifname = cand_bsr_ifname = NULL;
1016 srcmetric = srcpref = helloperiod = jpperiod = jpperiod_coef
1017 = granularity = datatimo = regsuptimo = probetime
1019 helloperiod_coef = jpperiod_coef = -1;
1021 for (vifi = 0, v = uvifs; vifi < numvifs ; ++vifi , ++v)
1022 v->config_attr = NULL;