1610 lines
37 KiB
C
1610 lines
37 KiB
C
|
/*
|
||
|
* Copyright (c) 1998 by the University of Southern California.
|
||
|
* All rights reserved.
|
||
|
*
|
||
|
* Permission to use, copy, modify, and distribute this software and
|
||
|
* its documentation in source and binary forms for lawful
|
||
|
* purposes and without fee is hereby granted, provided
|
||
|
* that the above copyright notice appear in all copies and that both
|
||
|
* the copyright notice and this permission notice appear in supporting
|
||
|
* documentation, and that any documentation, advertising materials,
|
||
|
* and other materials related to such distribution and use acknowledge
|
||
|
* that the software was developed by the University of Southern
|
||
|
* California and/or Information Sciences Institute.
|
||
|
* The name of the University of Southern California may not
|
||
|
* be used to endorse or promote products derived from this software
|
||
|
* without specific prior written permission.
|
||
|
*
|
||
|
* THE UNIVERSITY OF SOUTHERN CALIFORNIA DOES NOT MAKE ANY REPRESENTATIONS
|
||
|
* ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY PURPOSE. THIS SOFTWARE IS
|
||
|
* PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES,
|
||
|
* INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF
|
||
|
* MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, TITLE, AND
|
||
|
* NON-INFRINGEMENT.
|
||
|
*
|
||
|
* IN NO EVENT SHALL USC, OR ANY OTHER CONTRIBUTOR BE LIABLE FOR ANY
|
||
|
* SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES, WHETHER IN CONTRACT,
|
||
|
* TORT, OR OTHER FORM OF ACTION, ARISING OUT OF OR IN CONNECTION WITH,
|
||
|
* THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||
|
*
|
||
|
* Other copyrights might apply to parts of this software and are so
|
||
|
* noted when applicable.
|
||
|
*/
|
||
|
/*
|
||
|
* Questions concerning this software should be directed to
|
||
|
* Mickael Hoerdt (hoerdt@clarinet.u-strasbg.fr) LSIIT Strasbourg.
|
||
|
*
|
||
|
*/
|
||
|
/*
|
||
|
* This program has been derived from pim6dd.
|
||
|
* The pim6dd program is covered by the license in the accompanying file
|
||
|
* named "LICENSE.pim6dd".
|
||
|
*/
|
||
|
/*
|
||
|
* This program has been derived from pimd.
|
||
|
* The pimd program is covered by the license in the accompanying file
|
||
|
* named "LICENSE.pimd".
|
||
|
*
|
||
|
*/
|
||
|
/*
|
||
|
* Part of this program has been derived from mrouted.
|
||
|
* The mrouted program is covered by the license in the accompanying file
|
||
|
* named "LICENSE.mrouted".
|
||
|
*
|
||
|
* The mrouted program is COPYRIGHT 1989 by The Board of Trustees of
|
||
|
* Leland Stanford Junior University.
|
||
|
*
|
||
|
* $FreeBSD$
|
||
|
*/
|
||
|
|
||
|
|
||
|
#include <sys/ioctl.h>
|
||
|
#include <syslog.h>
|
||
|
#include <stdlib.h>
|
||
|
#include "vif.h"
|
||
|
#include "pim6.h"
|
||
|
#include "inet6.h"
|
||
|
#include "rp.h"
|
||
|
#include "pimd.h"
|
||
|
#include "timer.h"
|
||
|
#include "route.h"
|
||
|
#if defined(__FreeBSD__) && __FreeBSD__ >= 3
|
||
|
#include <net/if_var.h>
|
||
|
#endif
|
||
|
#include <netinet6/in6_var.h>
|
||
|
#include <string.h>
|
||
|
#include <errno.h>
|
||
|
#include <ctype.h>
|
||
|
#include "config.h"
|
||
|
#include <arpa/inet.h>
|
||
|
#include <stdio.h>
|
||
|
#include "debug.h"
|
||
|
|
||
|
void add_phaddr(struct uvif *v , struct sockaddr_in6 *addr,struct in6_addr *mask);
|
||
|
char *next_word(char **s);
|
||
|
int wordToOption(char *word);
|
||
|
int parse_phyint(char *s);
|
||
|
int parse_candidateRP(char *s);
|
||
|
int parse_group_prefix(char *s);
|
||
|
int parseBSR(char *s);
|
||
|
int parse_reg_threshold(char *s);
|
||
|
int parse_data_threshold(char *s);
|
||
|
int parse_default_source_metric(char *s);
|
||
|
int parse_default_source_preference(char *s);
|
||
|
int parse_hello_period(char *s);
|
||
|
int parse_granularity(char *s);
|
||
|
int parse_jp_period(char *s);
|
||
|
int parse_data_timeout(char *s);
|
||
|
int parse_register_suppression_timeout(char *s);
|
||
|
int parse_probe_time(char *s);
|
||
|
int parse_assert_timeout(char *s);
|
||
|
|
||
|
void
|
||
|
config_vifs_from_kernel()
|
||
|
{
|
||
|
struct ifreq *ifrp,*ifend;
|
||
|
register struct uvif *v;
|
||
|
register vifi_t vifi;
|
||
|
int n,i;
|
||
|
struct sockaddr_in6 addr;
|
||
|
struct in6_addr mask;
|
||
|
short flags;
|
||
|
int num_ifreq = 64;
|
||
|
struct ifconf ifc;
|
||
|
|
||
|
total_interfaces= 0; /* The total number of physical interfaces */
|
||
|
|
||
|
ifc.ifc_len = num_ifreq * sizeof (struct ifreq);
|
||
|
ifc.ifc_buf = calloc(ifc.ifc_len,sizeof(char));
|
||
|
while (ifc.ifc_buf) {
|
||
|
caddr_t newbuf;
|
||
|
|
||
|
if (ioctl(udp_socket,SIOCGIFCONF,(char *)&ifc) <0)
|
||
|
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
|
||
|
/*
|
||
|
* If the buffer was large enough to hold all the addresses
|
||
|
* then break out, otherwise increase the buffer size and
|
||
|
* try again.
|
||
|
*
|
||
|
* The only way to know that we definitely had enough space
|
||
|
* is to know that there was enough space for at least one
|
||
|
* more struct ifreq. ???
|
||
|
*/
|
||
|
if( (num_ifreq * sizeof (struct ifreq)) >=
|
||
|
ifc.ifc_len + sizeof(struct ifreq))
|
||
|
break;
|
||
|
|
||
|
num_ifreq *= 2;
|
||
|
ifc.ifc_len = num_ifreq * sizeof(struct ifreq);
|
||
|
newbuf = realloc(ifc.ifc_buf, ifc.ifc_len);
|
||
|
if (newbuf == NULL)
|
||
|
free(ifc.ifc_buf);
|
||
|
ifc.ifc_buf = newbuf;
|
||
|
}
|
||
|
if (ifc.ifc_buf == NULL)
|
||
|
log(LOG_ERR, 0, "config_vifs_from_kernel: ran out of memory");
|
||
|
|
||
|
|
||
|
ifrp = (struct ifreq *) ifc.ifc_buf;
|
||
|
ifend = (struct ifreq * ) (ifc.ifc_buf + ifc.ifc_len);
|
||
|
|
||
|
/*
|
||
|
* Loop through all of the interfaces.
|
||
|
*/
|
||
|
for(;ifrp < ifend;ifrp = (struct ifreq *)((char *)ifrp+n))
|
||
|
{
|
||
|
struct ifreq ifr;
|
||
|
struct in6_ifreq ifr6;
|
||
|
|
||
|
#ifdef HAVE_SA_LEN
|
||
|
n = ifrp->ifr_addr.sa_len + sizeof(ifrp->ifr_name);
|
||
|
if(n < sizeof(*ifrp))
|
||
|
n=sizeof(*ifrp);
|
||
|
#else
|
||
|
n=sizeof(*ifrp);
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Ignore any interface for an address family other than IPv6.
|
||
|
*/
|
||
|
if ( ifrp->ifr_addr.sa_family != AF_INET6)
|
||
|
{
|
||
|
/* Eventually may have IP address later */
|
||
|
total_interfaces++;
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
memcpy(&addr,&ifrp->ifr_addr,sizeof(struct sockaddr_in6));
|
||
|
|
||
|
/*
|
||
|
* Need a template to preserve address info that is
|
||
|
* used below to locate the next entry. (Otherwise,
|
||
|
* SIOCGIFFLAGS stomps over it because the requests
|
||
|
* are returned in a union.)
|
||
|
*/
|
||
|
memcpy(ifr.ifr_name,ifrp->ifr_name,sizeof(ifr.ifr_name));
|
||
|
memcpy(ifr6.ifr_name,ifrp->ifr_name,sizeof(ifr6.ifr_name));
|
||
|
|
||
|
if(ioctl(udp_socket,SIOCGIFFLAGS,(char *)&ifr) <0)
|
||
|
log(LOG_ERR, errno, "ioctl SIOCGIFFLAGS for %s", ifr.ifr_name);
|
||
|
flags = ifr.ifr_flags;
|
||
|
|
||
|
#if 0
|
||
|
/*
|
||
|
* Ignore loopback interfaces and interfaces that do not
|
||
|
* support multicast.
|
||
|
*/
|
||
|
if((flags & (IFF_LOOPBACK | IFF_MULTICAST ))!= IFF_MULTICAST)
|
||
|
continue;
|
||
|
#endif
|
||
|
|
||
|
/*
|
||
|
* Get netmask of the address.
|
||
|
*/
|
||
|
ifr6.ifr_addr = *(struct sockaddr_in6 *)&ifrp->ifr_addr;
|
||
|
if(ioctl(udp_socket, SIOCGIFNETMASK_IN6, (char *)&ifr6) <0)
|
||
|
log(LOG_ERR, errno, "ioctl SIOCGIFNETMASK_IN6 for %s",
|
||
|
inet6_fmt(&ifr6.ifr_addr.sin6_addr));
|
||
|
memcpy(&mask,&ifr6.ifr_addr.sin6_addr,sizeof(mask));
|
||
|
|
||
|
/*
|
||
|
* Get IPv6 specific flags, and ignore an anycast address.
|
||
|
* XXX: how about a deprecated, tentative, duplicated or
|
||
|
* detached address?
|
||
|
*/
|
||
|
ifr6.ifr_addr = *(struct sockaddr_in6 *)&ifrp->ifr_addr;
|
||
|
if (ioctl(udp_socket, SIOCGIFAFLAG_IN6, &ifr6) < 0) {
|
||
|
log(LOG_ERR, errno, "ioctl SIOCGIFAFLAG_IN6 for %s",
|
||
|
inet6_fmt(&ifr6.ifr_addr.sin6_addr));
|
||
|
}
|
||
|
else {
|
||
|
if (ifr6.ifr_ifru.ifru_flags6 & IN6_IFF_ANYCAST) {
|
||
|
log(LOG_DEBUG, 0, "config_vifs_from_kernel: "
|
||
|
"%s on %s is an anycast address, ignored",
|
||
|
inet6_fmt(&ifr6.ifr_addr.sin6_addr),
|
||
|
ifr.ifr_name);
|
||
|
continue;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if (IN6_IS_ADDR_LINKLOCAL(&addr.sin6_addr))
|
||
|
{
|
||
|
addr.sin6_scope_id = if_nametoindex(ifrp->ifr_name);
|
||
|
#ifdef __KAME__
|
||
|
/*
|
||
|
* Hack for KAME kernel.
|
||
|
* Set sin6_scope_id field of a link local address and clear
|
||
|
* the index embedded in the address.
|
||
|
*/
|
||
|
/* clear interface index */
|
||
|
addr.sin6_addr.s6_addr[2] = 0;
|
||
|
addr.sin6_addr.s6_addr[3] = 0;
|
||
|
#endif
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* If the address is connected to the same subnet as one
|
||
|
* already installed in the uvifs array, just add the address
|
||
|
* to the list of addresses of the uvif.
|
||
|
*/
|
||
|
for(vifi = 0, v = uvifs; vifi < numvifs; ++vifi, ++v)
|
||
|
{
|
||
|
if( strcmp(v->uv_name , ifr.ifr_name) == 0 )
|
||
|
{
|
||
|
add_phaddr(v, &addr,&mask);
|
||
|
break;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( vifi != numvifs )
|
||
|
continue;
|
||
|
|
||
|
/*
|
||
|
* If there is room in the uvifs array, install this interface.
|
||
|
*/
|
||
|
if( numvifs == MAXMIFS )
|
||
|
{
|
||
|
log(LOG_WARNING, 0,
|
||
|
"too many vifs, ignoring %s", ifr.ifr_name);
|
||
|
continue;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* Everyone below is a potential vif interface.
|
||
|
* We don't care if it has wrong configuration or not
|
||
|
* configured at all.
|
||
|
*/
|
||
|
total_interfaces++;
|
||
|
|
||
|
v = &uvifs[numvifs];
|
||
|
v->uv_dst_addr = allpim6routers_group;
|
||
|
v->uv_subnetmask = mask;
|
||
|
strncpy ( v->uv_name , ifr.ifr_name,IFNAMSIZ);
|
||
|
v->uv_ifindex = if_nametoindex(v->uv_name);
|
||
|
add_phaddr(v,&addr,&mask);
|
||
|
|
||
|
/* prefix local calc. (and what about add_phaddr?...) */
|
||
|
for (i = 0; i < sizeof(struct in6_addr); i++)
|
||
|
v->uv_prefix.sin6_addr.s6_addr[i] =
|
||
|
addr.sin6_addr.s6_addr[i] & mask.s6_addr[i];
|
||
|
|
||
|
if(flags & IFF_POINTOPOINT)
|
||
|
v->uv_flags |=(VIFF_REXMIT_PRUNES | VIFF_POINT_TO_POINT);
|
||
|
|
||
|
/*
|
||
|
* Disable multicast routing on loopback interfaces and
|
||
|
* interfaces that do not support multicast. But they are
|
||
|
* still necessary, since global addresses maybe assigned only
|
||
|
* on such interfaces.
|
||
|
*/
|
||
|
if ((flags & IFF_LOOPBACK) != 0 || (flags & IFF_MULTICAST) == 0)
|
||
|
v->uv_flags |= VIFF_DISABLED;
|
||
|
|
||
|
IF_DEBUG(DEBUG_IF)
|
||
|
log(LOG_DEBUG,0,
|
||
|
"Installing %s (%s on subnet %s) ,"
|
||
|
"as vif #%u - rate = %d",
|
||
|
v->uv_name,inet6_fmt(&addr.sin6_addr),
|
||
|
net6name(&v->uv_prefix.sin6_addr,&mask),
|
||
|
numvifs,v->uv_rate_limit);
|
||
|
|
||
|
++numvifs;
|
||
|
|
||
|
|
||
|
if( !(flags & IFF_UP))
|
||
|
{
|
||
|
v->uv_flags |= VIFF_DOWN;
|
||
|
vifs_down = TRUE;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
|
||
|
void
|
||
|
add_phaddr(struct uvif *v,struct sockaddr_in6 *addr,struct in6_addr *mask)
|
||
|
{
|
||
|
struct phaddr *pa;
|
||
|
int i;
|
||
|
|
||
|
if( (pa=malloc(sizeof(*pa))) == NULL)
|
||
|
log(LOG_ERR, 0, "add_phaddr: memory exhausted");
|
||
|
|
||
|
|
||
|
memset(pa,0,sizeof(*pa));
|
||
|
pa->pa_addr= *addr;
|
||
|
pa->pa_subnetmask = *mask;
|
||
|
|
||
|
for(i = 0; i < sizeof(struct in6_addr); i++)
|
||
|
pa->pa_prefix.sin6_addr.s6_addr[i] =
|
||
|
addr->sin6_addr.s6_addr[i] & mask->s6_addr[i];
|
||
|
pa->pa_prefix.sin6_scope_id = addr->sin6_scope_id;
|
||
|
|
||
|
|
||
|
if(IN6_IS_ADDR_LINKLOCAL(&addr->sin6_addr)) {
|
||
|
if(v->uv_linklocal)
|
||
|
log(LOG_WARNING, 0,
|
||
|
"add_phaddr: found more than one link-local "
|
||
|
"address on %s",
|
||
|
v->uv_name);
|
||
|
|
||
|
v->uv_linklocal = pa;
|
||
|
}
|
||
|
|
||
|
pa->pa_next = v->uv_addrs;
|
||
|
v->uv_addrs = pa;
|
||
|
}
|
||
|
|
||
|
void
|
||
|
config_vifs_from_file()
|
||
|
{
|
||
|
FILE *f;
|
||
|
char linebuf[100];
|
||
|
char *w,*s;
|
||
|
struct ifconf ifc;
|
||
|
int option;
|
||
|
char ifbuf[BUFSIZ];
|
||
|
u_int8 *data_ptr;
|
||
|
|
||
|
if((f=fopen(configfilename,"r"))==NULL)
|
||
|
{
|
||
|
if( errno != ENOENT)
|
||
|
log(LOG_ERR,errno,"Can't open %s",configfilename);
|
||
|
log(LOG_WARNING,errno,"Can't open %s",configfilename);
|
||
|
return;
|
||
|
}
|
||
|
/*
|
||
|
* Note that sizeof(pim6_enocd_uni_addr_t) might be larger than
|
||
|
* the length of the Encoded-Unicast-address field(18 byte) due to
|
||
|
* some padding put in the compiler. However, it doesn't matter
|
||
|
* since we use the space just as a buffer(i.e not as the message).
|
||
|
*/
|
||
|
cand_rp_adv_message.buffer = (u_int8 *)malloc( 4 + sizeof(pim6_encod_uni_addr_t) +
|
||
|
255*sizeof(pim6_encod_grp_addr_t));
|
||
|
if(cand_rp_adv_message.buffer == NULL)
|
||
|
log(LOG_ERR,errno,"Candrpadv Buffer allocation");
|
||
|
|
||
|
cand_rp_adv_message.prefix_cnt_ptr = cand_rp_adv_message.buffer;
|
||
|
|
||
|
/* By default, if no group_prefix configured, then prefix_cnt == 0
|
||
|
* implies group_prefix = ff::/8 and masklen = 8.
|
||
|
*/
|
||
|
|
||
|
*cand_rp_adv_message.prefix_cnt_ptr = 0;
|
||
|
cand_rp_adv_message.insert_data_ptr = cand_rp_adv_message.buffer;
|
||
|
|
||
|
/* TODO: XXX: HARDCODING!!! */
|
||
|
cand_rp_adv_message.insert_data_ptr += (4 + 18);
|
||
|
|
||
|
ifc.ifc_buf = ifbuf;
|
||
|
ifc.ifc_len = sizeof(ifbuf);
|
||
|
if(ioctl(udp_socket,SIOCGIFCONF,(char *)&ifc) < 0)
|
||
|
log(LOG_ERR, errno, "ioctl SIOCGIFCONF");
|
||
|
|
||
|
while( fgets(linebuf, sizeof(linebuf),f) != NULL )
|
||
|
{
|
||
|
s = linebuf;
|
||
|
w = next_word(&s);
|
||
|
option = wordToOption(w);
|
||
|
switch(option)
|
||
|
{
|
||
|
case EMPTY:
|
||
|
continue;
|
||
|
break;
|
||
|
case PHYINT:
|
||
|
parse_phyint(s);
|
||
|
break;
|
||
|
case CANDIDATE_RP:
|
||
|
parse_candidateRP(s);
|
||
|
break;
|
||
|
case GROUP_PREFIX:
|
||
|
parse_group_prefix(s);
|
||
|
break;
|
||
|
case BOOTSTRAP_RP:
|
||
|
parseBSR(s);
|
||
|
break;
|
||
|
case REG_THRESHOLD:
|
||
|
parse_reg_threshold(s);
|
||
|
break;
|
||
|
case DATA_THRESHOLD:
|
||
|
parse_data_threshold(s);
|
||
|
break;
|
||
|
case DEFAULT_SOURCE_METRIC:
|
||
|
parse_default_source_metric(s);
|
||
|
break;
|
||
|
case DEFAULT_SOURCE_PREFERENCE :
|
||
|
parse_default_source_preference(s);
|
||
|
break;
|
||
|
case HELLO_PERIOD :
|
||
|
parse_hello_period(s);
|
||
|
break;
|
||
|
case GRANULARITY :
|
||
|
parse_granularity(s);
|
||
|
break;
|
||
|
case JOIN_PRUNE_PERIOD :
|
||
|
parse_jp_period(s);
|
||
|
break;
|
||
|
case DATA_TIMEOUT :
|
||
|
parse_data_timeout(s);
|
||
|
break;
|
||
|
case REGISTER_SUPPRESSION_TIMEOUT :
|
||
|
parse_register_suppression_timeout(s);
|
||
|
break;
|
||
|
case PROBE_TIME :
|
||
|
parse_probe_time(s);
|
||
|
break;
|
||
|
case ASSERT_TIMEOUT:
|
||
|
parse_assert_timeout(s);
|
||
|
break;
|
||
|
default:
|
||
|
log(LOG_WARNING, 0, "unknown command '%s' in %s",
|
||
|
w, configfilename);
|
||
|
|
||
|
}
|
||
|
}
|
||
|
cand_rp_adv_message.message_size = cand_rp_adv_message.insert_data_ptr - cand_rp_adv_message.buffer;
|
||
|
if (cand_rp_flag != FALSE)
|
||
|
{
|
||
|
my_cand_rp_holdtime = 2.5 * my_cand_rp_adv_period;
|
||
|
|
||
|
/* TODO: HARDCODING! */
|
||
|
data_ptr = cand_rp_adv_message.buffer + 1; /* WARNING */
|
||
|
PUT_BYTE(my_cand_rp_priority,data_ptr);
|
||
|
PUT_HOSTSHORT(my_cand_rp_holdtime, data_ptr);
|
||
|
PUT_EUADDR6(my_cand_rp_address.sin6_addr,data_ptr);
|
||
|
IF_DEBUG(DEBUG_PIM_CAND_RP)
|
||
|
{
|
||
|
log(LOG_DEBUG, 0,
|
||
|
"Local Cand-RP address is : %s",
|
||
|
inet6_fmt(&my_cand_rp_address.sin6_addr));
|
||
|
log(LOG_DEBUG, 0,
|
||
|
"Local Cand-RP priority is : %u",my_cand_rp_priority);
|
||
|
log(LOG_DEBUG, 0,
|
||
|
"Local Cand-RP advertisement period is : %u sec.",
|
||
|
my_cand_rp_adv_period);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
if( cand_bsr_flag!=FALSE)
|
||
|
{
|
||
|
IF_DEBUG(DEBUG_PIM_BOOTSTRAP)
|
||
|
{
|
||
|
log(LOG_DEBUG, 0,
|
||
|
"Local BSR address: %s",
|
||
|
inet6_fmt(&my_bsr_address.sin6_addr));
|
||
|
log(LOG_DEBUG, 0,
|
||
|
"Local BSR priority : %u",my_bsr_priority);
|
||
|
log(LOG_DEBUG,0,
|
||
|
"Local BSR period is : %u sec.",
|
||
|
my_bsr_period);
|
||
|
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
IF_DEBUG(DEBUG_SWITCH)
|
||
|
{
|
||
|
log(LOG_DEBUG,0,"reg_rate_limit set to %u (bits/s)" , pim_reg_rate_bytes);
|
||
|
log(LOG_DEBUG,0,"reg_rate_interval set to %u s.",pim_reg_rate_check_interval);
|
||
|
log(LOG_DEBUG,0,"data_rate_limit set to %u (bits/s)" , pim_data_rate_bytes);
|
||
|
log(LOG_DEBUG,0,"data_rate_interval set to %u s.",pim_data_rate_check_interval);
|
||
|
}
|
||
|
|
||
|
IF_DEBUG(DEBUG_PIM_HELLO)
|
||
|
{
|
||
|
log(LOG_DEBUG,0, "pim_hello_period set to: %u", pim_hello_period);
|
||
|
log(LOG_DEBUG,0, "pim_hello_holdtime set to: %u", pim_hello_holdtime);
|
||
|
}
|
||
|
|
||
|
IF_DEBUG(DEBUG_PIM_JOIN_PRUNE)
|
||
|
{
|
||
|
log(LOG_DEBUG,0, "pim_join_prune_period set to: %u", pim_join_prune_period);
|
||
|
log(LOG_DEBUG,0, "pim_join_prune_holdtime set to: %u", pim_join_prune_holdtime);
|
||
|
}
|
||
|
|
||
|
fclose(f);
|
||
|
|
||
|
}
|
||
|
/*
|
||
|
* function name: wordToOption
|
||
|
* input: char *word, a pointer to the word
|
||
|
* output: int; a number corresponding to the code of the word
|
||
|
* operation: converts the result of the string comparisons into numerics.
|
||
|
* comments: called by config_vifs_from_file()
|
||
|
*/
|
||
|
|
||
|
int wordToOption(char *word)
|
||
|
{
|
||
|
if (EQUAL(word, ""))
|
||
|
return EMPTY;
|
||
|
if (EQUAL(word, "phyint"))
|
||
|
return PHYINT;
|
||
|
if (EQUAL(word, "cand_rp"))
|
||
|
return CANDIDATE_RP;
|
||
|
if (EQUAL(word, "group_prefix"))
|
||
|
return GROUP_PREFIX;
|
||
|
if (EQUAL(word, "cand_bootstrap_router"))
|
||
|
return BOOTSTRAP_RP;
|
||
|
if (EQUAL(word, "switch_register_threshold"))
|
||
|
return REG_THRESHOLD;
|
||
|
if (EQUAL(word, "switch_data_threshold"))
|
||
|
return DATA_THRESHOLD;
|
||
|
if (EQUAL(word, "default_source_metric"))
|
||
|
return DEFAULT_SOURCE_METRIC;
|
||
|
if (EQUAL(word, "default_source_preference"))
|
||
|
return DEFAULT_SOURCE_PREFERENCE;
|
||
|
if (EQUAL(word, "hello_period"))
|
||
|
return HELLO_PERIOD;
|
||
|
if (EQUAL(word, "granularity"))
|
||
|
return GRANULARITY;
|
||
|
if (EQUAL(word, "join_prune_period"))
|
||
|
return JOIN_PRUNE_PERIOD;
|
||
|
if (EQUAL(word, "data_timeout"))
|
||
|
return DATA_TIMEOUT;
|
||
|
if (EQUAL(word, "register_suppression_timeout"))
|
||
|
return REGISTER_SUPPRESSION_TIMEOUT;
|
||
|
if (EQUAL(word, "probe_time"))
|
||
|
return PROBE_TIME;
|
||
|
if (EQUAL(word, "assert_timeout"))
|
||
|
return PROBE_TIME;
|
||
|
return UNKNOWN;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* function name: parse_phyint
|
||
|
* input: char *s, pointing to the parsing point of the file
|
||
|
* output: int (TRUE if the parsing was successful, o.w. FALSE)
|
||
|
* operation: parses the physical interface file configurations, if any.
|
||
|
* The general form is:
|
||
|
* phyint <ifname> [disable] [preference <p>] [metric <m>]
|
||
|
*/
|
||
|
|
||
|
|
||
|
int parse_phyint(char *s)
|
||
|
{
|
||
|
char *w,c,*ifname;
|
||
|
vifi_t vifi;
|
||
|
struct uvif *v;
|
||
|
u_int n;
|
||
|
|
||
|
if(EQUAL((w = next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING, 0, "Missing phyint name in %s", configfilename);
|
||
|
return FALSE;
|
||
|
}
|
||
|
ifname = w;
|
||
|
|
||
|
for (vifi = 0,v=uvifs;vifi <= numvifs ; ++vifi , ++v)
|
||
|
{
|
||
|
if(vifi == numvifs)
|
||
|
{
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Invalid phyint name (maybe not configured..) '%s' "
|
||
|
"in %s", w, configfilename);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if(strcmp(v->uv_name,ifname))
|
||
|
continue;
|
||
|
|
||
|
while(!EQUAL((w = next_word(&s)),""))
|
||
|
{
|
||
|
if(EQUAL(w,"disable"))
|
||
|
v->uv_flags |=VIFF_DISABLED;
|
||
|
else if (EQUAL(w, "nolistener"))
|
||
|
v->uv_flags |= VIFF_NOLISTENER;
|
||
|
else
|
||
|
{
|
||
|
if(EQUAL(w,"preference"))
|
||
|
{
|
||
|
if(EQUAL((w=next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Missing preference for "
|
||
|
"phyint %s in %s",
|
||
|
ifname, configfilename);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (sscanf(w,"%u%c",&n,&c) != 1 ||
|
||
|
n < 1 || n > 255 )
|
||
|
{
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Invalid preference "
|
||
|
"'%s' for phyint %s "
|
||
|
"in %s",
|
||
|
w, ifname,
|
||
|
configfilename);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
IF_DEBUG(DEBUG_ASSERT)
|
||
|
log(LOG_DEBUG, 0,"Config setting default local preference on %d to %s",n,ifname);
|
||
|
v->uv_local_pref = n;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(EQUAL(w, "metric"))
|
||
|
{
|
||
|
if(EQUAL((w = next_word(&s)), ""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing metric for "
|
||
|
"phyint %s in %s",
|
||
|
ifname,
|
||
|
configfilename);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (sscanf(w, "%u%c", &n, &c) != 1 ||
|
||
|
n < 1 || n > 1024 )
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid metric '%s' for phyint %s in %s",
|
||
|
w, ifname,configfilename);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
IF_DEBUG(DEBUG_ASSERT)
|
||
|
log(LOG_DEBUG,0,
|
||
|
"Config setting default local metric on %d to %s.",
|
||
|
n,ifname);
|
||
|
v->uv_local_metric = n;
|
||
|
}
|
||
|
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
break;
|
||
|
}
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* function name: parse_candidateRP
|
||
|
* input: char *s
|
||
|
* output: int (TRUE if the parsing was successful, o.w. FALSE)
|
||
|
* operation: parses the candidate RP information.
|
||
|
* The general form is:
|
||
|
* 'cand_rp <ifname> [priority <number>] [time <number>]'.
|
||
|
*/
|
||
|
int
|
||
|
parse_candidateRP(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
struct sockaddr_in6 *sa6_rp;
|
||
|
u_int time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
|
||
|
u_int priority = PIM_DEFAULT_CAND_RP_PRIORITY;
|
||
|
|
||
|
sa6_rp = NULL;
|
||
|
cand_rp_flag = FALSE;
|
||
|
|
||
|
my_cand_rp_adv_period = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
|
||
|
|
||
|
while(!EQUAL((w = next_word(&s)),""))
|
||
|
{
|
||
|
if((!EQUAL(w,"priority")) && (!EQUAL(w,"time")))
|
||
|
{
|
||
|
/*
|
||
|
* if the interface is specified and is valid
|
||
|
* we take the max global address of the interface
|
||
|
* (aliasing) else look at the end of the function.
|
||
|
*/
|
||
|
sa6_rp = local_iface(w);
|
||
|
if(!sa6_rp)
|
||
|
log(LOG_WARNING, 0,
|
||
|
"cand_rp '%s' in %s is not configured."
|
||
|
"take the max local address the router..",
|
||
|
w, configfilename);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (EQUAL(w,"priority"))
|
||
|
{
|
||
|
if (EQUAL((w = next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing priority ; set to default "
|
||
|
": %d (0 is highest )",priority);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (sscanf(w,"%u",&priority)!= 1 )
|
||
|
{
|
||
|
priority = PIM_DEFAULT_CAND_RP_PRIORITY;
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Invalid priority '%' "
|
||
|
"for cand_rp;set to default "
|
||
|
"(0 is highest) : %d",
|
||
|
w, priority);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (EQUAL((w = next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Missing cand_adv period ;"
|
||
|
"set to default : %d",time);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (sscanf(w,"%u",&time)!= 1 )
|
||
|
{
|
||
|
time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Invalid cand_adv_period "
|
||
|
"'%s';set to default : %d",
|
||
|
w,time);
|
||
|
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( time > (my_cand_rp_adv_period = ~0))
|
||
|
time = my_cand_rp_adv_period;
|
||
|
else
|
||
|
if(time <10)
|
||
|
time = 10;
|
||
|
else
|
||
|
if (time > PIM_DEFAULT_CAND_RP_ADV_PERIOD)
|
||
|
time = PIM_DEFAULT_CAND_RP_ADV_PERIOD;
|
||
|
my_cand_rp_adv_period = time;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!sa6_rp)
|
||
|
sa6_rp= max_global_address();
|
||
|
|
||
|
my_cand_rp_address=*sa6_rp;
|
||
|
my_cand_rp_priority = priority;
|
||
|
my_cand_rp_adv_period = time;
|
||
|
cand_rp_flag = TRUE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* function name: parse_group_prefix
|
||
|
* input: char *s
|
||
|
* output: int
|
||
|
* operation: parse group_prefix configured information.
|
||
|
* General form: 'group_prefix <group-addr>/<prefix_len>'.
|
||
|
*/
|
||
|
int
|
||
|
parse_group_prefix(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
struct in6_addr group_addr;
|
||
|
u_int32 masklen=PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
|
||
|
|
||
|
w=next_word(&s);
|
||
|
if (EQUAL(w,""))
|
||
|
{
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Configuration error for 'group_prefix' in %s: no group_addr. "
|
||
|
"Ignoring...", configfilename);
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
w=strtok(w,"/");
|
||
|
|
||
|
if ( inet_pton(AF_INET6,w,(void *)&group_addr) != 1 )
|
||
|
{
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Config error in %s : Bad ddress formatt.Ignoring..",
|
||
|
configfilename);
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (!IN6_IS_ADDR_MULTICAST(&group_addr))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Config error in %s: '%s' is not a mcast addr.Ignoring",
|
||
|
configfilename,
|
||
|
inet6_fmt(&group_addr));
|
||
|
return FALSE;
|
||
|
}
|
||
|
if (!(~(*cand_rp_adv_message.prefix_cnt_ptr)))
|
||
|
{
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Too many group_prefix configured. Truncating...");
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
w=strtok(NULL,"/");
|
||
|
if(w==NULL)
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Config error in %s : missing group prefix.Ignoring..",
|
||
|
configfilename);
|
||
|
return FALSE;
|
||
|
}
|
||
|
if ( sscanf(w,"%u",&masklen) ==1 )
|
||
|
{
|
||
|
if (masklen > (sizeof(group_addr) * 8))
|
||
|
masklen = (sizeof(group_addr)*8);
|
||
|
else
|
||
|
if (masklen <PIM_GROUP_PREFIX_DEFAULT_MASKLEN)
|
||
|
masklen = PIM_GROUP_PREFIX_DEFAULT_MASKLEN;
|
||
|
}
|
||
|
|
||
|
|
||
|
PUT_EGADDR6(group_addr, (u_int8)masklen, 0,
|
||
|
cand_rp_adv_message.insert_data_ptr);
|
||
|
(*cand_rp_adv_message.prefix_cnt_ptr)++;
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
/*
|
||
|
* function name: parseBSR
|
||
|
* input: char *s
|
||
|
* output: int
|
||
|
* operation: parse the candidate BSR configured information.
|
||
|
* General form:
|
||
|
* 'cand_bootstrap_router <ifname> [priority <number>]'.
|
||
|
* this function is similar to parse_candrp
|
||
|
*/
|
||
|
|
||
|
int
|
||
|
parseBSR(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
struct sockaddr_in6 *sa6_bsr;
|
||
|
u_int32 priority = PIM_DEFAULT_BSR_PRIORITY;
|
||
|
u_int time = PIM_DEFAULT_BOOTSTRAP_PERIOD;
|
||
|
my_bsr_period = PIM_DEFAULT_BOOTSTRAP_PERIOD;
|
||
|
|
||
|
sa6_bsr = NULL;
|
||
|
cand_bsr_flag = FALSE;
|
||
|
|
||
|
while(!EQUAL((w = next_word(&s)),""))
|
||
|
{
|
||
|
if((!EQUAL(w,"priority")) && (!EQUAL(w,"time")))
|
||
|
{
|
||
|
|
||
|
sa6_bsr = local_iface(w);
|
||
|
if(!sa6_bsr)
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"cand_bootstrap_router '%s' in %s is not "
|
||
|
"configured.Take the max router address.",
|
||
|
w,configfilename);
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(EQUAL(w,"priority"))
|
||
|
{
|
||
|
if (EQUAL((w = next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Missing priority for the bsr;set to "
|
||
|
"default (0 is lowest): %d",priority);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (sscanf(w,"%u",&priority)!= 1 )
|
||
|
{
|
||
|
priority = PIM_DEFAULT_BSR_PRIORITY;
|
||
|
log(LOG_WARNING, 0,
|
||
|
"Invalid priority '%s'for "
|
||
|
"the bsr;set to default : %d",
|
||
|
w, priority);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( priority > (my_bsr_priority = ~0))
|
||
|
priority = my_bsr_priority;
|
||
|
my_bsr_priority = (u_int8)priority;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( EQUAL((w=next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing bsr period ;"
|
||
|
"set to default : %d ",time);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(sscanf(w,"%u",&time)!=1)
|
||
|
{
|
||
|
time=PIM_DEFAULT_BOOTSTRAP_PERIOD;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid bsr period"
|
||
|
"'%s';set to default : %d",
|
||
|
w,time);
|
||
|
}
|
||
|
else
|
||
|
my_bsr_period=time;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if(!sa6_bsr)
|
||
|
sa6_bsr = max_global_address();
|
||
|
|
||
|
my_bsr_address=*sa6_bsr;
|
||
|
my_bsr_priority = priority;
|
||
|
MASKLEN_TO_MASK6(RP_DEFAULT_IPV6_HASHMASKLEN,my_bsr_hash_mask);
|
||
|
cand_bsr_flag = TRUE;
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* function name: parse_reg_threshold
|
||
|
* input: char *s
|
||
|
* output: int (TRUE if successful, FALSE o.w.)
|
||
|
* operation: reads and assigns the switch to the spt threshold
|
||
|
* due to registers for the router, if used as RP.
|
||
|
* Maybe extended to support different thresholds
|
||
|
* for different groups(prefixes).
|
||
|
* General form:
|
||
|
* 'switch_register_threshold [rate <number> interval <number>]'.
|
||
|
* comments: called by config_vifs_from_file()
|
||
|
*/
|
||
|
|
||
|
|
||
|
int parse_reg_threshold(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int rate=PIM_DEFAULT_REG_RATE;
|
||
|
u_int interval= PIM_DEFAULT_REG_RATE_INTERVAL;
|
||
|
|
||
|
while(!EQUAL((w=next_word(&s)),""))
|
||
|
{
|
||
|
if(EQUAL(w,"rate"))
|
||
|
{
|
||
|
if(EQUAL((w=next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"switch_register_threshold : missing rate ; "
|
||
|
"set to default : %u (bits/s)",
|
||
|
rate);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(sscanf(w,"%u",&rate)!=1)
|
||
|
{
|
||
|
rate = PIM_DEFAULT_REG_RATE;
|
||
|
log(LOG_WARNING, 0,
|
||
|
"switch_register_threshold : "
|
||
|
"Invalid rate '%s' , set to defaut :"
|
||
|
" %u (bits/s)",
|
||
|
w,rate);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(EQUAL(w,"interval"))
|
||
|
{
|
||
|
if(EQUAL((w = next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,"switch_register_threshold : missing interval ; set to default : %u s.",
|
||
|
interval);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(sscanf(w,"%u",&interval) != 1)
|
||
|
{
|
||
|
interval = PIM_DEFAULT_REG_RATE_INTERVAL;
|
||
|
log(LOG_WARNING,0,"switch_register_threshold : Invalid interval '%s' ; set to default : %u s.",
|
||
|
w,interval);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
log(LOG_WARNING,0,"swhitch_register_threshold : Invalid parameter %s",w);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( interval < timer_interval)
|
||
|
{
|
||
|
interval = timer_interval;
|
||
|
log(LOG_WARNING,0,"switch_register_threshold : Interval too short , set to default : %u s.",
|
||
|
interval);
|
||
|
}
|
||
|
|
||
|
pim_reg_rate_bytes = (rate * interval ) /10;
|
||
|
pim_reg_rate_check_interval = interval;
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
/*
|
||
|
* function name: parse_data_threshold
|
||
|
* input: char *s
|
||
|
* output: int
|
||
|
* operation: reads and assigns the switch to the spt threshold
|
||
|
* due to data packets, if used as DR.
|
||
|
* General form:
|
||
|
* 'switch_data_threshold [rate <number> interval <number>]'.
|
||
|
* similar to register_threshold...
|
||
|
*/
|
||
|
|
||
|
int parse_data_threshold(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int rate=PIM_DEFAULT_DATA_RATE;
|
||
|
u_int interval= PIM_DEFAULT_DATA_RATE_INTERVAL;
|
||
|
|
||
|
while(!EQUAL((w=next_word(&s)),""))
|
||
|
{
|
||
|
if(EQUAL(w,"rate"))
|
||
|
{
|
||
|
if(EQUAL((w=next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,"switch_data_threshold : missing rate value ; set to defaut : %u (bits/s)",
|
||
|
rate);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(sscanf(w,"%u",&rate)!=1)
|
||
|
{
|
||
|
rate = PIM_DEFAULT_DATA_RATE;
|
||
|
log(LOG_WARNING,0,"switch_data_threshold : Invalid rate '%s' ; set to default : %u (bits/s)",
|
||
|
w,rate);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(EQUAL(w,"interval"))
|
||
|
{
|
||
|
if(EQUAL((w = next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,"switch_data_threshold : missing interval value ; set to default : %u s.",
|
||
|
interval);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if(sscanf(w,"%u",&interval) != 1)
|
||
|
{
|
||
|
interval = PIM_DEFAULT_DATA_RATE_INTERVAL;
|
||
|
log(LOG_WARNING,0,"switch_data_threshold : Invalid interval '%s' ; set to default : %u s.",
|
||
|
w,interval);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
log(LOG_WARNING,0,"swhitch_data_threshold :Invalid Parameter %s",w);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
if( interval < timer_interval)
|
||
|
{
|
||
|
interval = timer_interval;
|
||
|
log(LOG_WARNING,0,"switch_data_threshold : interval too short set to default : %u s.",
|
||
|
interval);
|
||
|
}
|
||
|
|
||
|
pim_data_rate_bytes = (rate * interval ) /10;
|
||
|
pim_data_rate_check_interval = interval;
|
||
|
|
||
|
return TRUE;
|
||
|
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* function name: parse_default_source_metric
|
||
|
* input: char *s
|
||
|
* output: int
|
||
|
* operation: reads and assigns the default source metric, if no reliable
|
||
|
* unicast routing information available.
|
||
|
* General form:
|
||
|
* 'default_source_metric <number>'.
|
||
|
* default pref and metric statements should precede all phyint
|
||
|
* statements in the config file.
|
||
|
*/
|
||
|
|
||
|
|
||
|
int parse_default_source_metric(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int value;
|
||
|
vifi_t vifi;
|
||
|
struct uvif *v;
|
||
|
|
||
|
value = DEFAULT_LOCAL_METRIC;
|
||
|
|
||
|
if (EQUAL((w = next_word(&s)), ""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing source metric value ; set to default %u",
|
||
|
value);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (sscanf(w, "%u", &value) != 1)
|
||
|
{
|
||
|
value = DEFAULT_LOCAL_METRIC;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid source metric value '%s' ;set to default %u",
|
||
|
w,value);
|
||
|
}
|
||
|
default_source_metric = value;
|
||
|
log(LOG_INFO,0, "Default_source_metric is : %u", default_source_metric);
|
||
|
|
||
|
for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v)
|
||
|
{
|
||
|
v->uv_local_metric = default_source_metric;
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* function name: parse_default_source_preference
|
||
|
* input: char *s
|
||
|
* output: int
|
||
|
* operation: reads and assigns the default source preference, if no reliable
|
||
|
* unicast routing information available.
|
||
|
* General form:
|
||
|
* 'default_source_preference <number>'.
|
||
|
* default pref and metric statements should precede all phyint
|
||
|
* statements in the config file.
|
||
|
*/
|
||
|
|
||
|
int parse_default_source_preference(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int value;
|
||
|
vifi_t vifi;
|
||
|
struct uvif *v;
|
||
|
|
||
|
value = DEFAULT_LOCAL_PREF;
|
||
|
|
||
|
if (EQUAL((w = next_word(&s)), ""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing source preference ; set to default %u",
|
||
|
value);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (sscanf(w, "%u", &value) != 1)
|
||
|
{
|
||
|
value = DEFAULT_LOCAL_PREF;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid source preference value '%s' ;set to default %u",
|
||
|
w,value);
|
||
|
}
|
||
|
default_source_preference = value;
|
||
|
log(LOG_INFO,0, "default_source_preference set to: %u", default_source_preference);
|
||
|
|
||
|
for (vifi = 0, v = uvifs; vifi < MAXVIFS; ++vifi, ++v)
|
||
|
{
|
||
|
v->uv_local_pref = default_source_preference;
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
* function name: parse_hello_period
|
||
|
* input: char *s
|
||
|
* output: int
|
||
|
* operation: reads and assigns the hello period for a pim router
|
||
|
* General form:
|
||
|
* 'hello_period <number> <coef>'.
|
||
|
* number is the period in second between 2 hello messages
|
||
|
* and coef is the coef to deterimine the hello holdtime
|
||
|
* default : 3.5
|
||
|
*/
|
||
|
|
||
|
int parse_hello_period(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int hellop;
|
||
|
float coef;
|
||
|
|
||
|
hellop = PIM_TIMER_HELLO_PERIOD;
|
||
|
coef = 3.5;
|
||
|
|
||
|
if (EQUAL((w = next_word(&s)), ""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing hello period ; set to default %u",
|
||
|
hellop);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (sscanf(w, "%u", &hellop) != 1)
|
||
|
{
|
||
|
hellop = PIM_TIMER_HELLO_PERIOD;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid hello period value '%s' ;set to default %u",
|
||
|
w,hellop);
|
||
|
}
|
||
|
pim_hello_period = hellop;
|
||
|
|
||
|
if (!EQUAL((w=next_word(&s)),""))
|
||
|
{
|
||
|
if (sscanf(w, "%f", &coef) != 1)
|
||
|
{
|
||
|
coef = 3.5;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid hello period coef '%s' ;set to default %.1f",
|
||
|
w,coef);
|
||
|
}
|
||
|
if(coef<=1)
|
||
|
{
|
||
|
coef = 3.5;
|
||
|
log(LOG_WARNING,0,
|
||
|
"for hello period coef must be > 1;set to default %.1f",
|
||
|
coef);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
pim_hello_holdtime = coef*pim_hello_period;
|
||
|
return(TRUE);
|
||
|
}
|
||
|
/*
|
||
|
* function name: parse_jp_period
|
||
|
* input: char *s
|
||
|
* output: int
|
||
|
* operation: reads and assigns the join/prune period for a pim router
|
||
|
* General form:
|
||
|
* 'join_prune_period <number> <coef>'.
|
||
|
* number is the period in second between 2 join/prune messages
|
||
|
* and coef is the coef to deterimine the join/prune holdtime
|
||
|
* default : 3.5
|
||
|
* This function is similar to the function above
|
||
|
*/
|
||
|
|
||
|
int parse_jp_period(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int jpp;
|
||
|
float coef;
|
||
|
|
||
|
jpp = PIM_JOIN_PRUNE_PERIOD;
|
||
|
coef = 3.5;
|
||
|
|
||
|
if (EQUAL((w = next_word(&s)), ""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing join/prune period ; set to default %u",
|
||
|
jpp);
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if (sscanf(w, "%u", &jpp) != 1)
|
||
|
{
|
||
|
jpp = PIM_JOIN_PRUNE_PERIOD;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid join/prune period value '%s' ;set to default %u",
|
||
|
w,jpp);
|
||
|
}
|
||
|
|
||
|
pim_join_prune_period = jpp;
|
||
|
|
||
|
if (!EQUAL((w=next_word(&s)),""))
|
||
|
{
|
||
|
if (sscanf(w, "%f", &coef) != 1)
|
||
|
{
|
||
|
coef = 3.5;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid join/prune period coef '%s' ;set to default %.1f",
|
||
|
w,coef);
|
||
|
}
|
||
|
if(coef<=1)
|
||
|
{
|
||
|
coef = 3.5;
|
||
|
log(LOG_WARNING,0,
|
||
|
"for join/prune period coef must be > 1;set to default %.1f",
|
||
|
coef);
|
||
|
}
|
||
|
|
||
|
}
|
||
|
|
||
|
|
||
|
}
|
||
|
pim_join_prune_holdtime = coef*pim_join_prune_period;
|
||
|
return(TRUE);
|
||
|
}
|
||
|
|
||
|
|
||
|
/* function name : parse_granularity
|
||
|
* input char *s
|
||
|
* output int
|
||
|
* operation : reads and assigns the granularity of the demon's timer
|
||
|
* General form :
|
||
|
* 'granularity <number>
|
||
|
* number is the period in seconds between each "tics" of the virtual time.
|
||
|
* default : 5 s.
|
||
|
*/
|
||
|
int parse_granularity(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int granu;
|
||
|
|
||
|
granu = DEFAULT_TIMER_INTERVAL;
|
||
|
|
||
|
if( EQUAL((w= next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing timer granularity ; set to default %u",
|
||
|
granu);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( sscanf(w,"%u",&granu)!=1)
|
||
|
{
|
||
|
granu=DEFAULT_TIMER_INTERVAL;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid timer granularity value '%s' ; set to default %u",
|
||
|
w,granu);
|
||
|
}
|
||
|
timer_interval = granu;
|
||
|
if(granu < 1)
|
||
|
{
|
||
|
granu = DEFAULT_TIMER_INTERVAL;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Timer granularity MUST be > 1! ; set to default %u",
|
||
|
granu);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
timer_interval = granu;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* function name : parse_data_timeout
|
||
|
* input char *s
|
||
|
* output int
|
||
|
* operation : reads and assigns the data_timeout of each (S,G)
|
||
|
* General form :
|
||
|
* 'data_timeout <number>
|
||
|
* default : 210 s.
|
||
|
*/
|
||
|
int parse_data_timeout(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int time;
|
||
|
|
||
|
time = PIM_DATA_TIMEOUT;
|
||
|
|
||
|
if( EQUAL((w= next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing data timeout ; set to default %u",
|
||
|
time);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( sscanf(w,"%u",&time)!=1)
|
||
|
{
|
||
|
time=PIM_DATA_TIMEOUT;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid data timeout value '%s' ; set to default %u",
|
||
|
w,time);
|
||
|
}
|
||
|
pim_data_timeout = time;
|
||
|
if(time < 1)
|
||
|
{
|
||
|
time = PIM_DATA_TIMEOUT;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Data timeout must be > 1! ; set to default %u",
|
||
|
time);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pim_data_timeout = time;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* function name : parse_register_suppression_timeout
|
||
|
* input char *s
|
||
|
* output int
|
||
|
* operation : reads and assigns the register_suppression_timeout
|
||
|
* General form :
|
||
|
* 'register_suppression_timeout <number>
|
||
|
* default : 60 s.
|
||
|
*/
|
||
|
int parse_register_suppression_timeout(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int time;
|
||
|
|
||
|
time = PIM_REGISTER_SUPPRESSION_TIMEOUT;
|
||
|
|
||
|
if( EQUAL((w= next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing register suppression timeout ; set to default %u",
|
||
|
time);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( sscanf(w,"%u",&time)!=1)
|
||
|
{
|
||
|
time=PIM_REGISTER_SUPPRESSION_TIMEOUT;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid register suppression timeout value '%s' ; set to default %u",
|
||
|
w,time);
|
||
|
}
|
||
|
pim_register_suppression_timeout = time;
|
||
|
if(time < 1)
|
||
|
{
|
||
|
time = PIM_REGISTER_SUPPRESSION_TIMEOUT;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Register suppression timeout must be > 1! ; set to default %u",
|
||
|
time);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pim_register_suppression_timeout = time;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* function name : parse_probe_time
|
||
|
* input char *s
|
||
|
* output int
|
||
|
* operation : reads and assigns the probe_time for null-register
|
||
|
* General form :
|
||
|
* 'probe_time <number>
|
||
|
* default : 5 s.
|
||
|
*/
|
||
|
int parse_probe_time(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int time;
|
||
|
|
||
|
time = PIM_REGISTER_PROBE_TIME;
|
||
|
|
||
|
if( EQUAL((w= next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing register probe time ; set to default %u",
|
||
|
time);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( sscanf(w,"%u",&time)!=1)
|
||
|
{
|
||
|
time=PIM_REGISTER_PROBE_TIME;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid register probe time value '%s' ; set to default %u",
|
||
|
w,time);
|
||
|
}
|
||
|
pim_register_probe_time = time;
|
||
|
if(time < 1)
|
||
|
{
|
||
|
time = PIM_REGISTER_SUPPRESSION_TIMEOUT;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Register probe time must be > 1! ; set to default %u",
|
||
|
time);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pim_register_probe_time = time;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
/* function name : parse_assert_timeout
|
||
|
* input char *s
|
||
|
* output int
|
||
|
* operation : reads and assigns the assert timeout
|
||
|
* General form :
|
||
|
* 'assert_timeout <number>
|
||
|
* default : 180 s.
|
||
|
*/
|
||
|
int parse_assert_timeout(char *s)
|
||
|
{
|
||
|
char *w;
|
||
|
u_int time;
|
||
|
|
||
|
time = PIM_ASSERT_TIMEOUT;
|
||
|
|
||
|
if( EQUAL((w= next_word(&s)),""))
|
||
|
{
|
||
|
log(LOG_WARNING,0,
|
||
|
"Missing assert time out; set to default %u",
|
||
|
time);
|
||
|
return FALSE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
if( sscanf(w,"%u",&time)!=1)
|
||
|
{
|
||
|
time=PIM_ASSERT_TIMEOUT;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Invalid assert time out value '%s' ; set to default %u",
|
||
|
w,time);
|
||
|
}
|
||
|
pim_assert_timeout = time;
|
||
|
if(time < 1)
|
||
|
{
|
||
|
time = PIM_ASSERT_TIMEOUT;
|
||
|
log(LOG_WARNING,0,
|
||
|
"Assert time out must be > 1! ; set to default %u",
|
||
|
time);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
pim_assert_timeout = time;
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
|
||
|
char *next_word(char **s)
|
||
|
{
|
||
|
char *w;
|
||
|
|
||
|
w = *s;
|
||
|
while (*w == ' ' || *w == '\t')
|
||
|
w++;
|
||
|
|
||
|
*s = w;
|
||
|
for(;;) {
|
||
|
switch (**s) {
|
||
|
case ' ' :
|
||
|
case '\t' :
|
||
|
**s = '\0';
|
||
|
(*s)++;
|
||
|
return(w);
|
||
|
case '\n' :
|
||
|
case '#' :
|
||
|
**s = '\0';
|
||
|
return(w);
|
||
|
case '\0' :
|
||
|
return(w);
|
||
|
default :
|
||
|
if (isascii(**s) && isupper(**s))
|
||
|
**s = tolower(**s);
|
||
|
(*s)++;
|
||
|
}
|
||
|
}
|
||
|
}
|