Esempio n. 1
0
File: main.c Progetto: tzuryby/pimd
int main(int argc, char *argv[])
{	
    int dummy, dummysigalrm, foreground = 0;
    struct timeval tv, difftime, curtime, lasttime, *timeout;
    fd_set rfds, readers;
    int nfds, n, i, secs, ch;
    struct sigaction sa;
    time_t boottime;
    struct option long_options[] = {
	{"config", 1, 0, 'c'},
	{"debug", 2, 0, 'd'},
	{"foreground", 0, 0, 'f'},
	{"disable-vifs", 0, 0, 'N'},
	{"help", 0, 0, 'h'},
	{"version", 0, 0, 'v'},
	{"quit-daemon", 0, 0, 'q'},
	{"reload-config", 0, 0, 'l'},
	{"show-routes", 0, 0, 'r'},
	/* {"show-cache", 0, 0, 'i'}, */
	/* {"show-debug", 0, 0, 'p'}, */
	{0, 0, 0, 0}
    };
    
    snprintf(versionstring, sizeof (versionstring), "pimd version %s", todaysversion);

    while ((ch = getopt_long (argc, argv, "c:d::fhlNP::vqr", long_options, NULL)) != EOF) {
	switch (ch) {
	    case 'c':
		configfilename = optarg;
		break;

	    case 'd':
		if (!optarg) {
		    debug = DEBUG_DEFAULT;
		} else {
		    char *p,*q;
		    size_t i, len;
		    struct debugname *d;

		    debug = 0;
		    p = optarg; q = NULL;
		    while (p) {
			q = strchr(p, ',');
			if (q)
			    *q++ = '\0';
			len = strlen(p);
			for (i = 0, d = debugnames; i < ARRAY_LEN(debugnames); i++, d++)
			    if (len >= d->nchars && strncmp(d->name, p, len) == 0)
				break;

			if (i == ARRAY_LEN(debugnames))
			    return usage();

			debug |= d->level;
			p = q;
		    }
		}
		break;

	    case 'f':
		foreground = 1;
		break;

	    case 'h':
		return usage();

	    case 'l':
		killshow(SIGHUP, NULL);
		return 0;

	    case 'N':
		disable_all_by_default = 1;
		break;

	    case 'P':
#ifdef SNMP
		if (!optarg)
		    dest_port = DEFAULT_PORT;
		else {
		    dest_port = strtonum(optarg, 1, 65535, &errstr);
		    if (errstr) {
			warnx("destination port %s", errstr);
			dest_port = DEFAULT_PORT;
		    }
		}
#else
		warnx("SNMP support missing, please feel free to submit a patch.");
#endif
		break;

	    case 'v':
		printf("%s\n", versionstring);
		return 0;

	    case 'q':
		killshow(SIGTERM, NULL);
		return 0;

	    case 'r':
		killshow(SIGUSR1, _PATH_PIMD_DUMP);
		return 0;
#if 0 /* XXX: TODO */
	    case 'i':
		killshow(SIGUSR2, _PATH_PIMD_CACHE);
		return 0;

	    case 'p':
		killshow(SIGQUIT, NULL);
		return 0;
#endif
	    default:
		return usage();
	}
    }

    argc -= optind;
    argv += optind;

    if (argc > 0) {
	return usage();
    }

    if (geteuid() != 0) {
	fprintf(stderr, "%s: must be root\n", __progname);
	exit(1);
    }
    setlinebuf(stderr);

    if (debug != 0) {
	struct debugname *d;
	char c;
	int tmpd = debug;

	fprintf(stderr, "debug level 0x%lx ", debug);
	c = '(';
	for (d = debugnames; d < debugnames + ARRAY_LEN(debugnames); d++) {
	    if ((tmpd & d->level) == d->level) {
		tmpd &= ~d->level;
		fprintf(stderr, "%c%s", c, d->name);
		c = ',';
	    }
	}
	fprintf(stderr, ")\n");
    }
    
    /*
     * Create directory for runtime files
     */
    mkdir(_PATH_PIMD_RUNDIR, 0755);

    /*
     * Setup logging
     */
#ifdef LOG_DAEMON
    (void)openlog("pimd", LOG_PID, LOG_DAEMON);
    (void)setlogmask(LOG_UPTO(LOG_NOTICE));
#else
    (void)openlog("pimd", LOG_PID);
#endif /* LOG_DAEMON */

    logit(LOG_DEBUG, 0, "%s starting", versionstring);

    do_randomize();
    time(&boottime);
    
    /* Start up the log rate-limiter */
    resetlogging(NULL);

    callout_init();
    init_igmp();
    init_pim();
#ifdef HAVE_ROUTING_SOCKETS
    init_routesock();
#endif /* HAVE_ROUTING_SOCKETS */
    init_pim_mrt();
    init_timers();
    
    /* TODO: check the kernel DVMRP/MROUTED/PIM support version */
    
#ifdef SNMP
    if (i = snmp_init())
	return i;
#endif /* SNMP */
    init_vifs();
    init_rp_and_bsr();   /* Must be after init_vifs() */
    
#ifdef RSRR
    rsrr_init();
#endif /* RSRR */
    
    sa.sa_handler = handler;
    sa.sa_flags = 0;	/* Interrupt system calls */
    sigemptyset(&sa.sa_mask);
    sigaction(SIGALRM, &sa, NULL);
    sigaction(SIGHUP, &sa, NULL);
    sigaction(SIGTERM, &sa, NULL);
    sigaction(SIGINT, &sa, NULL);
    sigaction(SIGUSR1, &sa, NULL);
    sigaction(SIGUSR2, &sa, NULL);
    
    FD_ZERO(&readers);
    FD_SET(igmp_socket, &readers);
    nfds = igmp_socket + 1;
    for (i = 0; i < nhandlers; i++) {
	FD_SET(ihandlers[i].fd, &readers);
	if (ihandlers[i].fd >= nfds)
	    nfds = ihandlers[i].fd + 1;
    }
    
    IF_DEBUG(DEBUG_IF)
	dump_vifs(stderr);
    IF_DEBUG(DEBUG_PIM_MRT)
	dump_pim_mrt(stderr);
    
    /* schedule first timer interrupt */
    timer_setTimer(TIMER_INTERVAL, timer, NULL);
    
    if (!debug && !foreground) {
	/* Detach from the terminal */
	haveterminal = 0;
	if (fork())
	    exit(0);
	(void)close(0);
	(void)close(1);
	(void)close(2);
	(void)open("/", 0);
	(void)dup2(0, 1);
	(void)dup2(0, 2);
#ifdef SYSV
	(void)setpgrp();
#else 
#ifdef TIOCNOTTY
	n = open("/dev/tty", 2);
	if (n >= 0) {
	    (void)ioctl(n, TIOCNOTTY, (char *)0);
	    (void)close(n);
	}
#else
	if (setsid() < 0)
	    perror("setsid");
#endif /* TIOCNOTTY */
#endif /* SYSV */
    } /* End of child process code */
    
    if (pidfile(NULL)) {
	warn("Cannot create pidfile");
    }

    /*
     * Main receive loop.
     */
    dummy = 0;
    dummysigalrm = SIGALRM;
    difftime.tv_usec = 0;
    gettimeofday(&curtime, NULL);
    lasttime = curtime;
    while (1) {
	memcpy(&rfds, &readers, sizeof(rfds));
	secs = timer_nextTimer();
	if (secs == -1)
	    timeout = NULL;
	else {
	    timeout = &tv;
	    timeout->tv_sec = secs;
	   timeout->tv_usec = 0;
        }

        if (boottime) {
           time_t n;

           time(&n);
           if (n > boottime + 15) {
              struct rp_hold *rph = g_rp_hold;

              while(rph) {
                 add_rp_grp_entry(&cand_rp_list, &grp_mask_list,
                                  rph->address, 1, (u_int16)0xffffff, rph->group, rph->mask,
                                  curr_bsr_hash_mask, curr_bsr_fragment_tag);
                 rph = rph->next;
              }
              boottime = 0;
           }
        }
	
	if (sighandled) {
	    if (sighandled & GOT_SIGINT) {
		sighandled &= ~GOT_SIGINT;
		break;
	    }
	    if (sighandled & GOT_SIGHUP) {
		sighandled &= ~GOT_SIGHUP;
		restart(SIGHUP);
		
		/* reconstruct readers and nfds */
		FD_ZERO(&readers);
		FD_SET(igmp_socket, &readers);
		nfds = igmp_socket + 1;
		for (i = 0; i < nhandlers; i++) {
		    FD_SET(ihandlers[i].fd, &readers);
		    if (ihandlers[i].fd >= nfds)
			nfds = ihandlers[i].fd + 1;
		}
		memcpy(&rfds, &readers, sizeof(rfds));
	    }
	    if (sighandled & GOT_SIGUSR1) {
		sighandled &= ~GOT_SIGUSR1;
		fdump(SIGUSR1);
	    }
	    if (sighandled & GOT_SIGUSR2) {
		sighandled &= ~GOT_SIGUSR2;
		cdump(SIGUSR2);
	    }
	    if (sighandled & GOT_SIGALRM) {
		sighandled &= ~GOT_SIGALRM;
		timer(&dummysigalrm);
	    }
	}
	if ((n = select(nfds, &rfds, NULL, NULL, timeout)) < 0) {
	    if (errno != EINTR) /* SIGALRM is expected */
		logit(LOG_WARNING, errno, "select failed");
	    continue;
	}
	if (n > 0) {
	    /* TODO: shall check first igmp_socket for better performance? */
	    for (i = 0; i < nhandlers; i++) {
		if (FD_ISSET(ihandlers[i].fd, &rfds)) {
		    (*ihandlers[i].func)(ihandlers[i].fd, &rfds);
		}
	    }
	}
    
	/*
	 * Handle timeout queue.
	 *
	 * If select + packet processing took more than 1 second,
	 * or if there is a timeout pending, age the timeout queue.
	 *
	 * If not, collect usec in difftime to make sure that the
	 * time doesn't drift too badly.
	 *
	 * If the timeout handlers took more than 1 second,
	 * age the timeout queue again.  XXX This introduces the
	 * potential for infinite loops!
	 */
	do {
	    /*
	     * If the select timed out, then there's no other
	     * activity to account for and we don't need to
	     * call gettimeofday.
	     */
	    if (n == 0) {
		curtime.tv_sec = lasttime.tv_sec + secs;
		curtime.tv_usec = lasttime.tv_usec;
		n = -1;	/* don't do this next time through the loop */
	    } else
		gettimeofday(&curtime, NULL);
	    difftime.tv_sec = curtime.tv_sec - lasttime.tv_sec;
	    difftime.tv_usec += curtime.tv_usec - lasttime.tv_usec;
	    while (difftime.tv_usec >= 1000000) {
		difftime.tv_sec++;
		difftime.tv_usec -= 1000000;
	    }
	    if (difftime.tv_usec < 0) {
		difftime.tv_sec--;
		difftime.tv_usec += 1000000;
	    }
	    lasttime = curtime;
	    if (secs == 0 || difftime.tv_sec > 0)
		age_callout_queue(difftime.tv_sec);
	    secs = -1;
	} while (difftime.tv_sec > 0);
    } /* Main loop */

    logit(LOG_NOTICE, 0, "%s exiting", versionstring);
    cleanup();
    exit(0);
}
Esempio n. 2
0
File: mrt.c Progetto: wgc1212/pimd
mrtentry_t *find_route(uint32_t source, uint32_t group, uint16_t flags, char create)
{
    srcentry_t *src	   = NULL;
    grpentry_t *grp	   = NULL;
    mrtentry_t *mrt	   = NULL;
    mrtentry_t *mrt_wc	   = NULL;
    mrtentry_t *mrt_pmbr   = NULL;
    mrtentry_t *mrt2	   = NULL;
    rpentry_t  *rp	   = NULL;
    rp_grp_entry_t *rp_grp = NULL;

    if (flags & (MRTF_SG | MRTF_WC)) {
	if (!IN_MULTICAST(ntohl(group))) {
	    logit(LOG_WARNING, 0, "find_route: Not a multicast group address (%s) ...",
		  inet_fmt(group, s1, sizeof(s1)));
	    return NULL;
	}
    }

    if (flags & MRTF_SG) {
	if (!inet_valid_host(source) && !IN_PIM_SSM_RANGE(group)) {
	    logit(LOG_WARNING, 0, "find_route: Not a valid host (%s) ...",
		  inet_fmt(source, s1, sizeof(s1)));
	    return NULL;
	}
    }

    if (create == DONT_CREATE) {
	if (flags & (MRTF_SG | MRTF_WC)) {
	    if (search_grplist(group, &grp) == FALSE) {
		/* Group not found. Return the (*,*,RP) entry */
		if (flags & MRTF_PMBR) {
		    rp = rp_match(group);
		    if (rp) {
			logit(LOG_DEBUG, 0 , "find_route: Group not found. Return the (*,*,RP) entry");
			return rp->mrtlink;
		    }
		}

		logit(LOG_DEBUG, 0 , "find_route: Not PMBR, return NULL");
		return NULL;
	    }

	    /* Search for the source */
	    if (flags & MRTF_SG) {
		if (search_grpmrtlink(grp, source, &mrt) == TRUE) {
		    /* Exact (S,G) entry found */
		    logit(LOG_DEBUG, 0 , "find_route: exact (S,G) entry found");
		    return mrt;
		}

		logit(LOG_DEBUG, 0 , "find_route:(S,G) entry not found");
	    }

	    /* No (S,G) entry. Return the (*,G) entry (if exist) */
	    if ((flags & MRTF_WC) && grp->grp_route) {
		logit(LOG_DEBUG, 0 , "find_route: No (S,G) entry. Return the (*,G) entry");
		return grp->grp_route;
	    }
	}

	/* Return the (*,*,RP) entry */
	if (flags & MRTF_PMBR) {
	    rp = NULL;
	    if (group != INADDR_ANY_N)
		rp = rp_match(group);
	    else if (source != INADDR_ANY_N)
		rp = rp_find(source);

	    if (rp) {
		logit(LOG_DEBUG, 0 , "find_route: Return the (*,*,RP) entry");
		return rp->mrtlink;
	    }
	}

	logit(LOG_DEBUG, 0 , "find_route: No SG|WC, return NULL");
	return NULL;
    }


    /* Creation allowed */

    if (flags & (MRTF_SG | MRTF_WC)) {
	grp = create_grpentry(group);
	if (!grp)
	    return NULL;

	if (IN_PIM_SSM_RANGE(group)) {
	    if (rp_match(group) == (rpentry_t *) NULL) {
		/* For SSM, virtual RP entry has to be created. RP is at local link 169.254.0.1
		   to be sure not to send any register messages outside, although sending them
		   has been disabled for SSM also in PIM protocol.
		   The address does not need to be really configured in any interface.
		   TODO: Avoid need for virtual RP by implementing SSM-specific state structures */
		add_rp_grp_entry(&cand_rp_list, &grp_mask_list, htonl(0xa9fe0001), 20, 90, group,
				 0xffffffff, curr_bsr_hash_mask, curr_bsr_fragment_tag);
	    }
	}

	if (!grp->active_rp_grp) {
	    rp_grp = rp_grp_match(group);
	    if (!rp_grp) {
		if (!grp->mrtlink && !grp->grp_route)
		    /* New created grpentry. Delete it. */
		    delete_grpentry(grp);

		return NULL;
	    }

	    rp = rp_grp->rp->rpentry;
	    grp->active_rp_grp = rp_grp;
	    grp->rpaddr = rp->address;

	    /* Link to the top of the rp_grp_chain */
	    grp->rpnext = rp_grp->grplink;
	    rp_grp->grplink = grp;
	    if (grp->rpnext)
		grp->rpnext->rpprev = grp;
	} else {
	    rp = grp->active_rp_grp->rp->rpentry;
	}
    }

    mrt_wc = mrt_pmbr = NULL;

    if (flags & MRTF_WC) {
	/* Setup the (*,G) routing entry */
	mrt_wc = create_mrtentry(NULL, grp, MRTF_WC);
	if (!mrt_wc) {
	    if (!grp->mrtlink)
		/* New created grpentry. Delete it. */
		delete_grpentry(grp);

	    return NULL;
	}

	if (mrt_wc->flags & MRTF_NEW) {
	    mrt_pmbr = rp->mrtlink;

	    /* Copy the oif list from the (*,*,RP) entry */
	    if (mrt_pmbr)
		VOIF_COPY(mrt_pmbr, mrt_wc);

	    mrt_wc->incoming = rp->incoming;
	    mrt_wc->upstream = rp->upstream;
	    mrt_wc->metric   = rp->metric;
	    mrt_wc->preference = rp->preference;
	    move_kernel_cache(mrt_wc, 0);
#ifdef RSRR
	    rsrr_cache_bring_up(mrt_wc);
#endif /* RSRR */
	}

	if (!(flags & MRTF_SG))
	    return mrt_wc;
    }

    if (flags & MRTF_SG) {
	/* Setup the (S,G) routing entry */
	src = create_srcentry(source);
	if (!src) {
	    /* TODO: XXX: The MRTF_NEW flag check may be misleading?? check */
	    if ((!grp->grp_route || (grp->grp_route && (grp->grp_route->flags & MRTF_NEW)))
		&& !grp->mrtlink) {
		/* New created grpentry. Delete it. */
		delete_grpentry(grp);
	    }

	    return NULL;
	}

	mrt = create_mrtentry(src, grp, MRTF_SG);
	if (!mrt) {
	    if ((!grp->grp_route
		 || (grp->grp_route && (grp->grp_route->flags & MRTF_NEW)))
		&& !grp->mrtlink) {
		/* New created grpentry. Delete it. */
		delete_grpentry(grp);
	    }

	    if (!src->mrtlink)
		/* New created srcentry. Delete it. */
		delete_srcentry(src);

	    return NULL;
	}

	if (mrt->flags & MRTF_NEW) {
	    mrt2 = grp->grp_route;
	    if (!mrt2)
		mrt2 = rp->mrtlink;

	    /* Copy the oif list from the existing (*,G) or (*,*,RP) entry */
	    if (mrt2) {
		VOIF_COPY(mrt2, mrt);
		if (flags & MRTF_RP) {
		    /* ~(S,G) prune entry */
		    mrt->incoming    = mrt2->incoming;
		    mrt->upstream    = mrt2->upstream;
		    mrt->metric      = mrt2->metric;
		    mrt->preference  = mrt2->preference;
		    mrt->flags      |= MRTF_RP;
		}
	    }

	    if (!(mrt->flags & MRTF_RP)) {
		mrt->incoming   = src->incoming;
		mrt->upstream   = src->upstream;
		mrt->metric     = src->metric;
		mrt->preference = src->preference;
	    }
	    move_kernel_cache(mrt, 0);
#ifdef RSRR
	    rsrr_cache_bring_up(mrt);
#endif /* RSRR */
	}

	return mrt;
    }

    if (flags & MRTF_PMBR) {
	/* Get/return the (*,*,RP) routing entry */
	if (group != INADDR_ANY_N)
	    rp = rp_match(group);
	else if (source != INADDR_ANY_N)
	    rp = rp_find(source);
	else
	    return NULL; /* source == group == INADDR_ANY */

	if (!rp)
	    return NULL;

	if (rp->mrtlink)
	    return rp->mrtlink;

	mrt = create_mrtentry(rp, NULL, MRTF_PMBR);
	if (!mrt)
	    return NULL;

	mrt->incoming   = rp->incoming;
	mrt->upstream   = rp->upstream;
	mrt->metric     = rp->metric;
	mrt->preference = rp->preference;

	return mrt;
    }

    return NULL;
}