1/* 2 * Kernel routing table readup by getmsg(2) 3 * Copyright (C) 1999 Michael Handler 4 * 5 * This file is part of GNU Zebra. 6 * 7 * GNU Zebra is free software; you can redistribute it and/or modify it 8 * under the terms of the GNU General Public License as published by the 9 * Free Software Foundation; either version 2, or (at your option) any 10 * later version. 11 * 12 * GNU Zebra is distributed in the hope that it will be useful, but 13 * WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * General Public License for more details. 16 * 17 * You should have received a copy of the GNU General Public License 18 * along with GNU Zebra; see the file COPYING. If not, write to the Free 19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 20 * 02111-1307, USA. 21 */ 22 23#include <zebra.h> 24 25#include "prefix.h" 26#include "log.h" 27#include "if.h" 28 29#include "zebra/rib.h" 30 31#include <sys/stream.h> 32#include <sys/tihdr.h> 33 34/* Solaris defines these in both <netinet/in.h> and <inet/in.h>, sigh */ 35#ifdef SUNOS_5 36#include <sys/tiuser.h> 37#ifndef T_CURRENT 38#define T_CURRENT MI_T_CURRENT 39#endif /* T_CURRENT */ 40#ifndef IRE_CACHE 41#define IRE_CACHE 0x0020 /* Cached Route entry */ 42#endif /* IRE_CACHE */ 43#ifndef IRE_HOST_REDIRECT 44#define IRE_HOST_REDIRECT 0x0200 /* Host route entry from redirects */ 45#endif /* IRE_HOST_REDIRECT */ 46#ifndef IRE_CACHETABLE 47#define IRE_CACHETABLE (IRE_CACHE | IRE_BROADCAST | IRE_LOCAL | \ 48 IRE_LOOPBACK) 49#endif /* IRE_CACHETABLE */ 50#undef IPOPT_EOL 51#undef IPOPT_NOP 52#undef IPOPT_LSRR 53#undef IPOPT_RR 54#undef IPOPT_SSRR 55#endif /* SUNOS_5 */ 56 57#include <inet/common.h> 58#include <inet/ip.h> 59#include <inet/mib2.h> 60 61/* device to read IP routing table from */ 62#ifndef _PATH_GETMSG_ROUTE 63#define _PATH_GETMSG_ROUTE "/dev/ip" 64#endif /* _PATH_GETMSG_ROUTE */ 65 66#define RT_BUFSIZ 8192 67 68void handle_route_entry (mib2_ipRouteEntry_t *routeEntry) 69{ 70 struct prefix_ipv4 prefix; 71 struct in_addr tmpaddr, gateway; 72 u_char zebra_flags = 0; 73 74 if (routeEntry->ipRouteInfo.re_ire_type & IRE_CACHETABLE) 75 return; 76 77 if (routeEntry->ipRouteInfo.re_ire_type & IRE_HOST_REDIRECT) 78 zebra_flags |= ZEBRA_FLAG_SELFROUTE; 79 80 prefix.family = AF_INET; 81 82 tmpaddr.s_addr = routeEntry->ipRouteDest; 83 prefix.prefix = tmpaddr; 84 85 tmpaddr.s_addr = routeEntry->ipRouteMask; 86 prefix.prefixlen = ip_masklen (tmpaddr); 87 88 gateway.s_addr = routeEntry->ipRouteNextHop; 89 90 rib_add_ipv4 (ZEBRA_ROUTE_KERNEL, zebra_flags, &prefix, 91 &gateway, 0, 0, 0, 0); 92} 93 94void route_read () 95{ 96 char storage[RT_BUFSIZ]; 97 98 struct T_optmgmt_req *TLIreq = (struct T_optmgmt_req *) storage; 99 struct T_optmgmt_ack *TLIack = (struct T_optmgmt_ack *) storage; 100 struct T_error_ack *TLIerr = (struct T_error_ack *) storage; 101 102 struct opthdr *MIB2hdr; 103 104 mib2_ipRouteEntry_t *routeEntry, *lastRouteEntry; 105 106 struct strbuf msgdata; 107 int flags, dev, retval, process; 108 109 if ((dev = open (_PATH_GETMSG_ROUTE, O_RDWR)) == -1) { 110 zlog_warn ("can't open %s: %s", _PATH_GETMSG_ROUTE, 111 strerror (errno)); 112 return; 113 } 114 115 TLIreq->PRIM_type = T_OPTMGMT_REQ; 116 TLIreq->OPT_offset = sizeof (struct T_optmgmt_req); 117 TLIreq->OPT_length = sizeof (struct opthdr); 118 TLIreq->MGMT_flags = T_CURRENT; 119 120 MIB2hdr = (struct opthdr *) &TLIreq[1]; 121 122 MIB2hdr->level = MIB2_IP; 123 MIB2hdr->name = 0; 124 MIB2hdr->len = 0; 125 126 msgdata.buf = storage; 127 msgdata.len = sizeof (struct T_optmgmt_req) + sizeof (struct opthdr); 128 129 flags = 0; 130 131 if (putmsg (dev, &msgdata, NULL, flags) == -1) { 132 zlog_warn ("putmsg failed: %s", strerror (errno)); 133 goto exit; 134 } 135 136 MIB2hdr = (struct opthdr *) &TLIack[1]; 137 msgdata.maxlen = sizeof (storage); 138 139 while (1) { 140 flags = 0; 141 retval = getmsg (dev, &msgdata, NULL, &flags); 142 143 if (retval == -1) { 144 zlog_warn ("getmsg(ctl) failed: %s", strerror (errno)); 145 goto exit; 146 } 147 148 /* This is normal loop termination */ 149 if (retval == 0 && 150 msgdata.len >= sizeof (struct T_optmgmt_ack) && 151 TLIack->PRIM_type == T_OPTMGMT_ACK && 152 TLIack->MGMT_flags == T_SUCCESS && 153 MIB2hdr->len == 0) 154 break; 155 156 if (msgdata.len >= sizeof (struct T_error_ack) && 157 TLIerr->PRIM_type == T_ERROR_ACK) { 158 zlog_warn ("getmsg(ctl) returned T_ERROR_ACK: %s", 159 strerror ((TLIerr->TLI_error == TSYSERR) 160 ? TLIerr->UNIX_error : EPROTO)); 161 break; 162 } 163 164 /* should dump more debugging info to the log statement, 165 like what GateD does in this instance, but not 166 critical yet. */ 167 if (retval != MOREDATA || 168 msgdata.len < sizeof (struct T_optmgmt_ack) || 169 TLIack->PRIM_type != T_OPTMGMT_ACK || 170 TLIack->MGMT_flags != T_SUCCESS) { 171 errno = ENOMSG; 172 zlog_warn ("getmsg(ctl) returned bizarreness"); 173 break; 174 } 175 176 /* MIB2_IP_21 is the the pseudo-MIB2 ipRouteTable 177 entry, see <inet/mib2.h>. "This isn't the MIB data 178 you're looking for." */ 179 process = (MIB2hdr->level == MIB2_IP && 180 MIB2hdr->name == MIB2_IP_21) ? 1 : 0; 181 182 /* getmsg writes the data buffer out completely, not 183 to the closest smaller multiple. Unless reassembling 184 data structures across buffer boundaries is your idea 185 of a good time, set maxlen to the closest smaller 186 multiple of the size of the datastructure you're 187 retrieving. */ 188 msgdata.maxlen = sizeof (storage) - (sizeof (storage) 189 % sizeof (mib2_ipRouteEntry_t)); 190 191 msgdata.len = 0; 192 flags = 0; 193 194 do { 195 retval = getmsg (dev, NULL, &msgdata, &flags); 196 197 if (retval == -1) { 198 zlog_warn ("getmsg(data) failed: %s", 199 strerror (errno)); 200 goto exit; 201 } 202 203 if (!(retval == 0 || retval == MOREDATA)) { 204 zlog_warn ("getmsg(data) returned %d", retval); 205 goto exit; 206 } 207 208 if (process) { 209 if (msgdata.len % 210 sizeof (mib2_ipRouteEntry_t) != 0) { 211 zlog_warn ("getmsg(data) returned " 212"msgdata.len = %d (%% sizeof (mib2_ipRouteEntry_t) != 0)", msgdata.len); 213 goto exit; 214 } 215 216 routeEntry = (mib2_ipRouteEntry_t *) 217 msgdata.buf; 218 lastRouteEntry = (mib2_ipRouteEntry_t *) 219 (msgdata.buf + msgdata.len); 220 do { 221 handle_route_entry (routeEntry); 222 } while (++routeEntry < lastRouteEntry); 223 } 224 } while (retval == MOREDATA); 225 } 226 227exit: 228 close (dev); 229} 230