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 + -
显示快捷键?