ospfd_linux.c

来自「BCAST Implementation for NS2」· C语言 代码 · 共 1,100 行 · 第 1/2 页

C
1,100
字号
/* *   OSPFD routing daemon *   Copyright (C) 1998 by John T. Moy *    *   This program is free software; you can redistribute it and/or *   modify it under the terms of the GNU General Public License *   as published by the Free Software Foundation; either version 2 *   of the License, or (at your option) any later version. *    *   This program is distributed in the hope that it will be useful, *   but WITHOUT ANY WARRANTY; without even the implied warranty of *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the *   GNU General Public License for more details. *    *   You should have received a copy of the GNU General Public License *   along with this program; if not, write to the Free Software *   Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */#include <stdio.h>#include <stdlib.h>#include <sys/types.h>#include <sys/time.h>#include <sys/resource.h>#include <unistd.h>#include <tcl.h>#if LINUX_VERSION_CODE >= LINUX22#include <asm/types.h>#include <sys/socket.h>#include <linux/netlink.h>#include <linux/rtnetlink.h>#else#include <sys/socket.h>#endif#include <net/route.h>#include <sys/ioctl.h>#include <sys/uio.h>#include <linux/version.h>#include <net/if.h>#include <netinet/in.h>#include <arpa/inet.h>#include <errno.h>#include <signal.h>#include <syslog.h>// Hack to include mroute.h file#define _LINUX_SOCKIOS_H#define _LINUX_IN_H#include <linux/mroute.h>#include <netinet/ip.h>#include <linux/if_tunnel.h>#include <net/if_arp.h>#include "../src/ospfinc.h"#include "../src/monitor.h"#include "../src/system.h"#include "tcppkt.h"#include "linux.h"#include "ospfd_linux.h"#include <time.h>LinuxOspfd *ospfd_sys;char buffer[MAX_IP_PKTSIZE];// External declarationsbool get_prefix(char *prefix, InAddr &net, InMask &mask);/* Signal handlers */void timer(int){    signal(SIGALRM, timer);    ospfd_sys->one_second_timer();}void quit(int){    ospfd_sys->changing_routerid = false;    ospf->shutdown(10);}void reconfig(int){    signal(SIGUSR1, reconfig);    ospfd_sys->read_config();}/* The main OSPF loop. Loops getting messages (packets, timer * ticks, configuration messages, etc.) and never returns * until the OSPF process is told to exit. */int main(int, char * []){    int n_fd;    itimerval itim;    fd_set fdset;    fd_set wrset;    sigset_t sigset, osigset;    sys = ospfd_sys = new LinuxOspfd();    syslog(LOG_INFO, "Starting v%d.%d",	   OSPF::vmajor, OSPF::vminor);    // Read configuration    ospfd_sys->read_config();    if (!ospf) {	syslog(LOG_ERR, "ospfd initialization failed");	exit(1);    }    // Set up signals    signal(SIGALRM, timer);    signal(SIGHUP, quit);    signal(SIGTERM, quit);    signal(SIGUSR1, reconfig);    itim.it_interval.tv_sec = 1;    itim.it_value.tv_sec = 1;    itim.it_interval.tv_usec = 0;    itim.it_value.tv_usec = 0;    if (setitimer(ITIMER_REAL, &itim, NULL) < 0)	syslog(LOG_ERR, "setitimer: %m");    sigemptyset(&sigset);    sigaddset(&sigset, SIGALRM);    sigaddset(&sigset, SIGHUP);    sigaddset(&sigset, SIGTERM);    sigaddset(&sigset, SIGUSR1);    // Block signals in OSPF code    sigprocmask(SIG_BLOCK, &sigset, &osigset);    while (1) {	int msec_tmo;	int err;	FD_ZERO(&fdset);	FD_ZERO(&wrset);	n_fd = ospfd_sys->netfd;	FD_SET(ospfd_sys->netfd, &fdset);	ospfd_sys->mon_fd_set(n_fd, &fdset, &wrset);	if (ospfd_sys->igmpfd != -1) {	    FD_SET(ospfd_sys->igmpfd, &fdset);	    n_fd = MAX(n_fd, ospfd_sys->igmpfd);	}	if (ospfd_sys->rtsock != -1) {	    FD_SET(ospfd_sys->rtsock, &fdset);	    n_fd = MAX(n_fd, ospfd_sys->rtsock);	}	// Process any pending timers	ospf->tick();	// Time till next timer firing	msec_tmo = ospf->timeout();	// Flush any logging messages	ospf->logflush();	// Allow signals during select	sigprocmask(SIG_SETMASK, &osigset, NULL);	if (msec_tmo != -1) {	    timeval timeout;	    timeout.tv_sec = msec_tmo/1000;	    timeout.tv_usec = (msec_tmo % 1000) * 1000;	    err = select(n_fd+1, &fdset, &wrset, 0, &timeout);	}	else	    err = select(n_fd+1, &fdset, &wrset, 0, 0);	// Handle errors in select	if (err == -1 && errno != EINTR) {	    syslog(LOG_ERR, "select failed %m");	    exit(1);	}	// Check for change of Router ID	ospfd_sys->process_routerid_change();	// Update elapsed time	ospfd_sys->time_update();	// Block signals in OSPF code	sigprocmask(SIG_BLOCK, &sigset, &osigset);	// Process received data packet, if any	if (err <= 0)	    continue;	if (FD_ISSET(ospfd_sys->netfd, &fdset))	    ospfd_sys->raw_receive(ospfd_sys->netfd);	if (ospfd_sys->igmpfd != -1 &&	    FD_ISSET(ospfd_sys->igmpfd, &fdset))	    ospfd_sys->raw_receive(ospfd_sys->igmpfd);	if (ospfd_sys->rtsock != -1 &&	    FD_ISSET(ospfd_sys->rtsock, &fdset))	    ospfd_sys->netlink_receive(ospfd_sys->rtsock);	// Process monitor queries and responses	ospfd_sys->process_mon_io(&fdset, &wrset);    }}/* Process packets received on a raw socket. Could * be either the OSPF socket or the IGMP socket. */void LinuxOspfd::raw_receive(int fd){    int plen;    int rcvint = -1;#if LINUX_VERSION_CODE < LINUX22    unsigned int fromlen;    plen = recvfrom(fd, buffer, sizeof(buffer), 0, 0, &fromlen);    if (plen < 0) {        syslog(LOG_ERR, "recvfrom: %m");	return;    }#else    msghdr msg;    iovec iov;    byte cmsgbuf[128];    msg.msg_name = 0;    msg.msg_namelen = 0;    iov.iov_len = sizeof(buffer);    iov.iov_base = buffer;    msg.msg_iov = &iov;    msg.msg_iovlen = 1;    msg.msg_control = cmsgbuf;    msg.msg_controllen = sizeof(cmsgbuf);    plen = recvmsg(fd, &msg, 0);    if (plen < 0) {        syslog(LOG_ERR, "recvmsg: %m");	return;    }    else {	cmsghdr *cmsg;	for (cmsg = CMSG_FIRSTHDR(&msg); cmsg;	     cmsg = CMSG_NXTHDR(&msg, cmsg)) {	    if (cmsg->cmsg_level == SOL_IP &&		cmsg->cmsg_type == IP_PKTINFO) {	        in_pktinfo *pktinfo;		pktinfo = (in_pktinfo *) CMSG_DATA(cmsg);		rcvint = pktinfo->ipi_ifindex;		break;	    }	}    }#endif    // Dispatch based on IP protocol    InPkt *pkt = (InPkt *) buffer;    switch (pkt->i_prot) {        MCache *ce;      case PROT_OSPF:        ospf->rxpkt(rcvint, pkt, plen);	break;      case PROT_IGMP:        ospf->rxigmp(rcvint, pkt, plen);	break;      case 0:	ce = ospf->mclookup(ntoh32(pkt->i_src), ntoh32(pkt->i_dest));	sys->add_mcache(ntoh32(pkt->i_src), ntoh32(pkt->i_dest), ce);	break;      default:	break;    }}/* Received a packet over the rtnetlink interface. * This indicates that an interface has changed state, or that * a interface address has been added or deleted. * Note: because of some oddities in the Linux kernel, sometimes * adding an interface address generates bogus DELADDRs, resulting * in an extra reconfiguration. * * Changes in interface flags potentially cause the OSPF * API routines phy_up() or phy_down() to be called. All other * interface or address changes simply cause OSPF to be reconfigured. * * The netlink interface is available only in Linux 2.2 or later. */#if LINUX_VERSION_CODE >= LINUX22void LinuxOspfd::netlink_receive(int fd){    int plen;    unsigned int fromlen;    nlmsghdr *msg;    BSDPhyInt *phyp;    plen = recvfrom(fd, buffer, sizeof(buffer), 0, 0, &fromlen);    if (plen <= 0) {        syslog(LOG_ERR, "rtnetlink recvfrom: %m");	return;    }    for (msg = (nlmsghdr *)buffer; NLMSG_OK(msg, (uns32)plen);	 msg = NLMSG_NEXT(msg, plen)) {        switch (msg->nlmsg_type) {            in_addr in;	    ifinfomsg *ifinfo;	    ifaddrmsg *ifm;	    rtattr *rta;	    int rta_len;	    rtmsg *rtm;	    InAddr net;	    InMask mask;	    nlmsgerr *errmsg;          case RTM_NEWLINK:	// Interface flags change	    ifinfo = (ifinfomsg *)NLMSG_DATA(msg);	    syslog(LOG_NOTICE, "Ifc change IfIndex %d flags 0x%x",		   ifinfo->ifi_index, ifinfo->ifi_flags);	      read_config();	    break;	  case RTM_DELLINK:	// Interface deletion	    ifinfo = (ifinfomsg *)NLMSG_DATA(msg);	    syslog(LOG_NOTICE, "Ifc deleted IfIndex %d",		   ifinfo->ifi_index);	    read_config();	    break;          case RTM_NEWADDR: // Interface address add/delete          case RTM_DELADDR:	    ifm = (ifaddrmsg *)NLMSG_DATA(msg);	    rta_len = IFA_PAYLOAD(msg);	    for (rta = IFA_RTA(ifm); RTA_OK(rta, rta_len); 		 rta = RTA_NEXT(rta, rta_len)) {	        switch(rta->rta_type) {		  case IFA_ADDRESS:		    memcpy(&in.s_addr, RTA_DATA(rta), 4);		    break;	          default:		    break;		}	    }	    syslog(LOG_NOTICE, "Interface addr change %s", inet_ntoa(in));	    if (msg->nlmsg_type == RTM_DELADDR &&	        (phyp = (BSDPhyInt *) phyints.find(ifm->ifa_index, 0)) &&		!(ifm->ifa_flags & IFA_F_SECONDARY)) {	        set_flags(phyp, phyp->flags & ~IFF_UP);	    }	    read_config();	    break;          case RTM_NEWROUTE:          case RTM_DELROUTE:	    rtm = (rtmsg *)NLMSG_DATA(msg);	    if (rtm->rtm_protocol != PROT_OSPF)	        break;	    rta_len = RTM_PAYLOAD(msg);	    net = in.s_addr = 0;	    mask = 0;	    if (rtm->rtm_dst_len != 0) {	        for (rta = RTM_RTA(rtm); RTA_OK(rta, rta_len); 		     rta = RTA_NEXT(rta, rta_len)) {		    switch(rta->rta_type) {		      case RTA_DST:			memcpy(&in.s_addr, RTA_DATA(rta), 4);			break;		      default:			break;		    }		}		mask = ~((1 << (32-rtm->rtm_dst_len)) - 1);		net = ntoh32(in.s_addr) & mask;	    }	    if (msg->nlmsg_type == RTM_DELROUTE) {	        syslog(LOG_NOTICE, "Krt Delete %s", inet_ntoa(in));		ospf->krt_delete_notification(net, mask);	    }	    else if (dumping_remnants)	        ospf->remnant_notification(net, mask);	    break;	  case NLMSG_DONE:	    dumping_remnants = false;	    break;          case NLMSG_OVERRUN:	    syslog(LOG_ERR, "Overrun on routing socket: %m");	    break;	  case NLMSG_ERROR:	    errmsg = (nlmsgerr *)NLMSG_DATA(msg);	    // Sometimes we try to delete routes that aren't there	    // We ignore the resulting error messages	    if (errmsg->msg.nlmsg_type != RTM_DELROUTE)	    syslog(LOG_ERR, "Netlink error %d", errmsg->error);	    break;	  default:	    break;	}    }}#elsevoid LinuxOspfd::netlink_receive(int){}#endif/* Update the program's notion of time, which is in milliseconds * since program start. Wait until receiving the timer signal * to update a full second. */void LinuxOspfd::time_update(){    timeval now;	// Current idea of time    int timediff;    (void) gettimeofday(&now, NULL);    timediff = 1000*(now.tv_sec - last_time.tv_sec);    timediff += (now.tv_usec - last_time.tv_usec)/1000;    if ((timediff + sys_etime.msec) < 1000)	sys_etime.msec += timediff;    last_time = now;}/* Signal handler for the one second timer. * Up the elapsed time to the next whole second. */void LinuxOspfd::one_second_timer(){    timeval now;	// Current idea of time    (void) gettimeofday(&now, NULL);    sys_etime.sec++;     sys_etime.msec = 0;    last_time = now;}/* Initialize the Linux interface. * Open the network interface. * Start the random number generator. */char *ospfd_log_file = "/var/log/ospfd.log";LinuxOspfd::LinuxOspfd() : Linux(OSPFD_MON_PORT){    rlimit rlim;    next_phyint = 0;    (void) gettimeofday(&last_time, NULL);    changing_routerid = false;    change_complete = false;    dumping_remnants = false;    // No current VIFs    for (int i = 0; i < MAXVIFS; i++)        vifs[i] = 0;    // Allow core files    rlim.rlim_max = RLIM_INFINITY;    (void) setrlimit(RLIMIT_CORE, &rlim);    // Open syslog    openlog("ospfd", LOG_PID, LOG_DAEMON);    // Open log file    if (!(logstr = fopen(ospfd_log_file, "w"))) {	syslog(LOG_ERR, "Logfile open failed: %m");	exit(1);    }    // Open monitoring listen socket    monitor_listen();    // Open network    if ((netfd = socket(AF_INET, SOCK_RAW, PROT_OSPF)) == -1) {	syslog(LOG_ERR, "Network open failed: %m");	exit(1);    }    // We will supply headers on output    int hincl = 1;    setsockopt(netfd, IPPROTO_IP, IP_HDRINCL, &hincl, sizeof(hincl));    rtsock = -1;#if LINUX_VERSION_CODE >= LINUX22    // Request notification of receiving interface    int pktinfo = 1;    setsockopt(netfd, IPPROTO_IP, IP_PKTINFO, &pktinfo, sizeof(pktinfo));    // Open rtnetlink socket    nlm_seq = 0;    sockaddr_nl addr;    if ((rtsock = socket(PF_NETLINK, SOCK_RAW, NETLINK_ROUTE)) == -1) {	syslog(LOG_ERR, "Failed to create rtnetlink socket: %m");	exit(1);    }    addr.nl_family = AF_NETLINK;    addr.nl_pad = 0;    addr.nl_pid = 0;    addr.nl_groups = (RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE);    if (bind(rtsock, (sockaddr *)&addr, sizeof(addr)) < 0) {	syslog(LOG_ERR, "Failed to bind to rtnetlink socket: %m");	exit(1);    }#endif    // Open ioctl socket    if ((udpfd = socket(AF_INET, SOCK_DGRAM, 0)) < 0) {	syslog(LOG_ERR, "Failed to open UDP socket: %m");	exit(1);    }    // Start random number generator    srand(getpid());    // Will open multicast fd if requested to later    igmpfd = -1;}/* Destructor not expected to be called during the life * of the program. */LinuxOspfd::~LinuxOspfd(){}/* TCL procedures to send configuration data to the ospfd * application. */int SetRouterID(ClientData, Tcl_Interp *, int, char *argv[]);int SendGeneral(ClientData, Tcl_Interp *, int, char *argv[]);int SendArea(ClientData, Tcl_Interp *, int, char *argv[]);int SendAggregate(ClientData, Tcl_Interp *, int, char *argv[]);int SendHost(ClientData, Tcl_Interp *, int, char *argv[]);int SendInterface(ClientData, Tcl_Interp *, int, char *argv[]);int SendVL(ClientData, Tcl_Interp *, int, char *argv[]);int SendNeighbor(ClientData, Tcl_Interp *, int, char *argv[]);int SendExtRt(ClientData, Tcl_Interp *, int, char *argv[]);int SendMD5Key(ClientData, Tcl_Interp *, int, char *argv[]);/* Read the ospfd config out of the file /etc/ospfd.conf */char *ospfd_tcl_src = "/ospfd.tcl";char *ospfd_config_file = "/etc/ospfd.conf";rtid_t new_router_id;void LinuxOspfd::read_config(){    Tcl_Interp *interp; // Interpretation of config commands    char sendcfg[] = "sendcfg";    int namlen;    char *filename;    // In process of changing router ID?    if (changing_routerid)        return;    syslog(LOG_NOTICE, "reconfiguring");    new_router_id = 0;    interp = Tcl_CreateInterp();    // Install C-language TCl commands    Tcl_CreateCommand(interp, "routerid", SetRouterID, 0, 0);    Tcl_CreateCommand(interp, "sendgen", SendGeneral, 0, 0);    Tcl_CreateCommand(interp, "sendarea", SendArea, 0, 0);    Tcl_CreateCommand(interp, "sendagg", SendAggregate, 0, 0);    Tcl_CreateCommand(interp, "sendhost", SendHost, 0, 0);    Tcl_CreateCommand(interp, "sendifc", SendInterface, 0, 0);    Tcl_CreateCommand(interp, "sendvl", SendVL, 0, 0);    Tcl_CreateCommand(interp, "sendnbr", SendNeighbor, 0, 0);    Tcl_CreateCommand(interp, "sendextrt", SendExtRt, 0, 0);    Tcl_CreateCommand(interp, "sendmd5", SendMD5Key, 0, 0);    // Read additional TCL commands    namlen = strlen(INSTALL_DIR) + strlen(ospfd_tcl_src);    filename = new char[namlen+1];    strcpy(filename, INSTALL_DIR);    strcat(filename, ospfd_tcl_src);    if (Tcl_EvalFile(interp, filename) != TCL_OK)	syslog(LOG_INFO, "No additional TCL commands");

⌨️ 快捷键说明

复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?