📄 system.c
字号:
/* Add/modify a kernel routing table entry. * Multipath is not supported, so just use the first path * found in the routing table entry. * If there is no next hop pointer, it means that there * is either a) and unresolved next hop or b) and entry * whose interface has been deleted, but the router-LSA * not yet reoriginated. In either case, just delete * the routing table entry. */void LinuxOspfd::rtadd(InAddr net, InMask mask, MPath *mpp, MPath *ompp, bool reject){ if (directs.find(net, mask)) return; if (!mpp) { rtdel(net, mask, ompp); return; } if (ompp) rtdel(net, mask, ompp); rtentry_prepare(net, mask, mpp); // Reject route? if (reject) m.rt_flags |= RTF_REJECT; else m.rt_flags |= (RTF_UP | RTF_GATEWAY); // Add through ioctl if (-1 == ioctl(udpfd, SIOCADDRT, (char *)&m)) { if (errno == EEXIST) { ioctl(udpfd, SIOCDELRT, (char *)&m); if (-1 != ioctl(udpfd, SIOCADDRT, (char *)&m)) return; } syslog(LOG_ERR, "SIOCADDRT: %m"); }}/* Delete a kernel routing table entry. */void LinuxOspfd::rtdel(InAddr net, InMask mask, MPath *ompp){ if (directs.find(net, mask)) return; rtentry_prepare(net, mask, ompp); // Delete through ioctl if (-1 == ioctl(udpfd, SIOCDELRT, (char *)&m)) syslog(LOG_ERR, "SIOCDELRT: %m");}/* Uploading remnant routing table entries is not supported * on older Linux versions. */void LinuxOspfd::upload_remnants(){}#else/* On Linux 2.2, add and delete routing table entries * via the rtnetlink interface. Note that we are setting * rtm_protocol to 89. The Linux kernel doesn't do anything * special with the value, but it allows us to delete entries * freely without worrying that we will bash some other * routing daemon's entries. We should register the rtm_protocol * value with the Linux guys. */void LinuxOspfd::rtadd(InAddr net, InMask mask, MPath *mpp, MPath *ompp, bool reject){ nlmsghdr *nlm; rtmsg *rtm; rtattr *rta_dest; rtattr *rta_gw; int size; int prefix_length; if (directs.find(net, mask) || !mpp) { rtdel(net, mask, ompp); return; } // Change mask to prefix length for (prefix_length = 32; prefix_length > 0; prefix_length--) { if ((mask & (1 << (32-prefix_length))) != 0) break; } // Calculate size of routing message size = NLMSG_SPACE(sizeof(*rtm)); // Routing message itself if (prefix_length > 0) size += RTA_SPACE(4); // For destination if (!reject) size += RTA_SPACE(4); // For next hop // Allocate routing table message, and find place for // individual data items nlm = (nlmsghdr *) new char[size]; nlm->nlmsg_len = size; nlm->nlmsg_type = RTM_NEWROUTE; nlm->nlmsg_flags = NLM_F_REQUEST|NLM_F_REPLACE|NLM_F_CREATE; nlm->nlmsg_seq = nlm_seq++; nlm->nlmsg_pid = 0; rtm = (rtmsg *) NLMSG_DATA(nlm); rtm->rtm_family = AF_INET; rtm->rtm_dst_len = prefix_length; rtm->rtm_src_len = 0; rtm->rtm_tos = 0; rtm->rtm_table = 0; rtm->rtm_protocol = PROT_OSPF; rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_type = RTN_UNICAST; rtm->rtm_flags = 0; if (prefix_length > 0) { uns32 swnet; int attrlen; rta_dest = (rtattr *) RTM_RTA(rtm); rta_dest->rta_len = attrlen = RTA_SPACE(4); rta_dest->rta_type = RTA_DST; swnet = hton32(net); memcpy(RTA_DATA(rta_dest), &swnet, sizeof(swnet)); rta_gw = (rtattr *) RTA_NEXT(rta_dest, attrlen); } else rta_gw = (rtattr *) RTM_RTA(rtm); // Reject route? if (reject) { rtm->rtm_scope = RT_SCOPE_HOST; rtm->rtm_type = RTN_UNREACHABLE; } else { InAddr gw; BSDPhyInt *phyp=0; int phyint; gw = hton32(mpp->NHs[0].gw); if ((phyint = mpp->NHs[0].phyint) != -1) phyp = (BSDPhyInt *)phyints.find(phyint, 0); if (phyp && (phyp->flags & IFF_POINTOPOINT) != 0){ // Fill in gw attribute rta_gw->rta_len = RTA_SPACE(sizeof(phyint)); rta_gw->rta_type = RTA_OIF; memcpy(RTA_DATA(rta_gw), &phyint, sizeof(phyint)); } else { // Fill in gw attribute rta_gw->rta_len = RTA_SPACE(4); rta_gw->rta_type = RTA_GATEWAY; memcpy(RTA_DATA(rta_gw), &gw, sizeof(gw)); } } // Add through routing socket send if (-1 == send(rtsock, nlm, size, 0)) syslog(LOG_ERR, "add route through routing socket: %m"); delete [] ((char *)nlm);}void LinuxOspfd::rtdel(InAddr net, InMask mask, MPath *){ nlmsghdr *nlm; rtmsg *rtm; rtattr *rta_dest; int size; int prefix_length; // Change mask to prefix length for (prefix_length = 32; prefix_length > 0; prefix_length--) { if ((mask & (1 << (32-prefix_length))) != 0) break; } // Calculate size of routing message size = NLMSG_SPACE(sizeof(*rtm)); // Routing message itself if (prefix_length > 0) size += RTA_SPACE(4); // For destination // Allocate routing table message, and find place for // individual data items nlm = (nlmsghdr *) new char[size]; nlm->nlmsg_len = size; nlm->nlmsg_type = RTM_DELROUTE; nlm->nlmsg_flags = NLM_F_REQUEST; nlm->nlmsg_seq = nlm_seq++; nlm->nlmsg_pid = 0; rtm = (rtmsg *) NLMSG_DATA(nlm); rtm->rtm_family = AF_INET; rtm->rtm_dst_len = prefix_length; rtm->rtm_src_len = 0; rtm->rtm_tos = 0; rtm->rtm_table = 0; rtm->rtm_protocol = PROT_OSPF; rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_type = RTN_UNICAST; rtm->rtm_flags = 0; if (prefix_length > 0) { uns32 swnet; int attrlen; rta_dest = (rtattr *) RTM_RTA(rtm); rta_dest->rta_len = attrlen = RTA_SPACE(4); rta_dest->rta_type = RTA_DST; swnet = hton32(net); memcpy(RTA_DATA(rta_dest), &swnet, sizeof(swnet)); } // Delete through routing socket send if (-1 == send(rtsock, nlm, size, 0)) syslog(LOG_ERR, "del route through routing socket: %m"); delete [] ((char *)nlm);}/* Request the kernel to upload the current set of routing * table entries that it has. */void LinuxOspfd::upload_remnants(){ nlmsghdr *nlm; rtmsg *rtm; int size; // Set state to dumping dumping_remnants = true; // Calculate size of netlink message size = NLMSG_SPACE(sizeof(*rtm)); // Only a routing message // Allocate netlink message nlm = (nlmsghdr *) new char[size]; nlm->nlmsg_len = size; nlm->nlmsg_type = RTM_GETROUTE; nlm->nlmsg_flags = NLM_F_REQUEST | NLM_F_DUMP; nlm->nlmsg_seq = nlm_seq++; nlm->nlmsg_pid = 0; rtm = (rtmsg *) NLMSG_DATA(nlm); rtm->rtm_family = AF_INET; rtm->rtm_dst_len = 0; rtm->rtm_src_len = 0; rtm->rtm_tos = 0; rtm->rtm_table = 0; rtm->rtm_protocol = PROT_OSPF; rtm->rtm_scope = RT_SCOPE_UNIVERSE; rtm->rtm_type = RTN_UNICAST; rtm->rtm_flags = 0; // Send to routing socket if (-1 == send(rtsock, nlm, size, 0)) syslog(LOG_ERR, "routing table dump: %m"); delete [] ((char *)nlm);}#endif/* Add a multicast routing table entry to the kernel. */void LinuxOspfd::add_mcache(InAddr src, InAddr grp, MCache *e){ mfcctl mfe; int i; // Initially set to drop matching packets mfe.mfcc_origin.s_addr = hton32(src); mfe.mfcc_mcastgrp.s_addr = hton32(grp); mfe.mfcc_parent = 0; for (i = 0; i < MAXVIFS; i++) mfe.mfcc_ttls[i] = 255; // Now fill in with MOSPF information if (e) { BSDPhyInt *phyp; if (e->n_upstream && (phyp=(BSDPhyInt *)phyints.find(*e->up_phys, 0))) mfe.mfcc_parent = phyp->vifno; for (i = 0; i < e->n_downstream; i++) { if (e->down_str[i].nbr_addr != 0) // NBMA multicast not supported by Linux continue; if (!(phyp = (BSDPhyInt *)phyints.find(e->down_str[i].phyint, 0))) continue; if (phyp->vifno == 0) continue; // Linux ignores TTL 0, so bump to 1 in that case if ((mfe.mfcc_ttls[phyp->vifno] = e->down_str[i].ttl) == 0) mfe.mfcc_ttls[phyp->vifno] = 1; } } if (setsockopt(igmpfd, IPPROTO_IP, MRT_ADD_MFC, &mfe, sizeof(mfe)) == -1) syslog(LOG_ERR, "MRT_ADD_MFC failed: %m");}/* Delete a multicast routing table entry from the kernel. */void LinuxOspfd::del_mcache(InAddr src, InAddr grp){ mfcctl mfe; mfe.mfcc_origin.s_addr = hton32(src); mfe.mfcc_mcastgrp.s_addr = hton32(grp); if (setsockopt(igmpfd, IPPROTO_IP, MRT_DEL_MFC, &mfe, sizeof(mfe)) == -1) syslog(LOG_ERR, "MRT_DEL_MFC failed: %m");}/* Return the printable name of a physical interface. */char *LinuxOspfd::phyname(int phyint){ BSDPhyInt *phyp; phyp = (BSDPhyInt *)phyints.find(phyint, 0); return(phyp ? (char *) phyp->phyname : 0);}/* Print an OSPF logging message into the * log file. */void LinuxOspfd::sys_spflog(int msgno, char *msgbuf){ time_t t; tm *tp; t = time(0); tp = localtime(&t); fprintf(logstr, "%02d:%02d:%02d OSPF.%03d: %s\n", tp->tm_hour, tp->tm_min, tp->tm_sec, msgno, msgbuf); fflush(logstr);}/* Exit the ospfd program, printing a diagnostic message in * the process. */void LinuxOspfd::halt(int code, char *string){ syslog(LOG_ERR, "Exiting: %s, code %d", string, code); if (code != 0) abort(); else if (changing_routerid) change_complete = true; else exit(0);}/* Store the hitless restart parameters in the file * /etc/ospfd.restart. These are regular TCL commands, which * will get read again when the ospfd restarts. */const char *ospfd_rst_file = "/etc/ospfd.restart";void LinuxOspfd::store_hitless_parms(int grace_period, int n, MD5Seq *sns){ FILE *f; extern rtid_t new_router_id; in_addr addr; if (!(f = fopen(ospfd_rst_file, "w"))) { syslog(LOG_ERR, "Can't open %s for writing: %m", ospfd_rst_file); return; } fprintf(f, "grace_period %d\n", grace_period); addr.s_addr = hton32(new_router_id); fprintf(f, "routerid %s\n", inet_ntoa(addr)); for (int i = 0; i < n; i++) { if (sns[i].if_addr != 0) { addr.s_addr = hton32(sns[i].if_addr); fprintf(f, "interface %s 1\n", inet_ntoa(addr)); } else fprintf(f, "interface %s 1\n", phyname(sns[i].phyint)); fprintf(f, "md5_seqno %d\n", sns[i].seqno); } fclose(f);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -