1/* FIB SNMP. 2 * Copyright (C) 1999 Kunihiro Ishiguro 3 * 4 * This file is part of GNU Zebra. 5 * 6 * GNU Zebra is free software; you can redistribute it and/or modify it 7 * under the terms of the GNU General Public License as published by the 8 * Free Software Foundation; either version 2, or (at your option) any 9 * later version. 10 * 11 * GNU Zebra is distributed in the hope that it will be useful, but 12 * WITHOUT ANY WARRANTY; without even the implied warranty of 13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 14 * General Public License for more details. 15 * 16 * You should have received a copy of the GNU General Public License 17 * along with GNU Zebra; see the file COPYING. If not, write to the Free 18 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 19 * 02111-1307, USA. 20 */ 21 22#include <zebra.h> 23 24#ifdef HAVE_SNMP 25#include <net-snmp/net-snmp-config.h> 26#include <net-snmp/net-snmp-includes.h> 27 28#include "if.h" 29#include "log.h" 30#include "prefix.h" 31#include "command.h" 32#include "smux.h" 33#include "table.h" 34 35#include "zebra/rib.h" 36#include "zebra/zserv.h" 37 38#define IPFWMIB 1,3,6,1,2,1,4,24 39 40/* ipForwardTable */ 41#define IPFORWARDDEST 1 42#define IPFORWARDMASK 2 43#define IPFORWARDPOLICY 3 44#define IPFORWARDNEXTHOP 4 45#define IPFORWARDIFINDEX 5 46#define IPFORWARDTYPE 6 47#define IPFORWARDPROTO 7 48#define IPFORWARDAGE 8 49#define IPFORWARDINFO 9 50#define IPFORWARDNEXTHOPAS 10 51#define IPFORWARDMETRIC1 11 52#define IPFORWARDMETRIC2 12 53#define IPFORWARDMETRIC3 13 54#define IPFORWARDMETRIC4 14 55#define IPFORWARDMETRIC5 15 56 57/* ipCidrRouteTable */ 58#define IPCIDRROUTEDEST 1 59#define IPCIDRROUTEMASK 2 60#define IPCIDRROUTETOS 3 61#define IPCIDRROUTENEXTHOP 4 62#define IPCIDRROUTEIFINDEX 5 63#define IPCIDRROUTETYPE 6 64#define IPCIDRROUTEPROTO 7 65#define IPCIDRROUTEAGE 8 66#define IPCIDRROUTEINFO 9 67#define IPCIDRROUTENEXTHOPAS 10 68#define IPCIDRROUTEMETRIC1 11 69#define IPCIDRROUTEMETRIC2 12 70#define IPCIDRROUTEMETRIC3 13 71#define IPCIDRROUTEMETRIC4 14 72#define IPCIDRROUTEMETRIC5 15 73#define IPCIDRROUTESTATUS 16 74 75#define INTEGER32 ASN_INTEGER 76#define GAUGE32 ASN_GAUGE 77#define ENUMERATION ASN_INTEGER 78#define ROWSTATUS ASN_INTEGER 79#define IPADDRESS ASN_IPADDRESS 80#define OBJECTIDENTIFIER ASN_OBJECT_ID 81 82extern struct zebra_t zebrad; 83 84oid ipfw_oid [] = { IPFWMIB }; 85 86/* Hook functions. */ 87static u_char * ipFwNumber (struct variable *, oid [], size_t *, 88 int, size_t *, WriteMethod **); 89static u_char * ipFwTable (struct variable *, oid [], size_t *, 90 int, size_t *, WriteMethod **); 91static u_char * ipCidrNumber (struct variable *, oid [], size_t *, 92 int, size_t *, WriteMethod **); 93static u_char * ipCidrTable (struct variable *, oid [], size_t *, 94 int, size_t *, WriteMethod **); 95 96struct variable zebra_variables[] = 97 { 98 {0, GAUGE32, RONLY, ipFwNumber, 1, {1}}, 99 {IPFORWARDDEST, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 1}}, 100 {IPFORWARDMASK, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 2}}, 101 {IPFORWARDPOLICY, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 3}}, 102 {IPFORWARDNEXTHOP, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 4}}, 103 {IPFORWARDIFINDEX, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 5}}, 104 {IPFORWARDTYPE, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 6}}, 105 {IPFORWARDPROTO, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 7}}, 106 {IPFORWARDAGE, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 8}}, 107 {IPFORWARDINFO, OBJECTIDENTIFIER, RONLY, ipFwTable, 3, {2, 1, 9}}, 108 {IPFORWARDNEXTHOPAS, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 10}}, 109 {IPFORWARDMETRIC1, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 11}}, 110 {IPFORWARDMETRIC2, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 12}}, 111 {IPFORWARDMETRIC3, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 13}}, 112 {IPFORWARDMETRIC4, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 14}}, 113 {IPFORWARDMETRIC5, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 15}}, 114 {0, GAUGE32, RONLY, ipCidrNumber, 1, {3}}, 115 {IPCIDRROUTEDEST, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 1}}, 116 {IPCIDRROUTEMASK, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 2}}, 117 {IPCIDRROUTETOS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 3}}, 118 {IPCIDRROUTENEXTHOP, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 4}}, 119 {IPCIDRROUTEIFINDEX, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 5}}, 120 {IPCIDRROUTETYPE, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 6}}, 121 {IPCIDRROUTEPROTO, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 7}}, 122 {IPCIDRROUTEAGE, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 8}}, 123 {IPCIDRROUTEINFO, OBJECTIDENTIFIER, RONLY, ipCidrTable, 3, {4, 1, 9}}, 124 {IPCIDRROUTENEXTHOPAS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 10}}, 125 {IPCIDRROUTEMETRIC1, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 11}}, 126 {IPCIDRROUTEMETRIC2, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 12}}, 127 {IPCIDRROUTEMETRIC3, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 13}}, 128 {IPCIDRROUTEMETRIC4, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 14}}, 129 {IPCIDRROUTEMETRIC5, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 15}}, 130 {IPCIDRROUTESTATUS, ROWSTATUS, RONLY, ipCidrTable, 3, {4, 1, 16}} 131 }; 132 133 134static u_char * 135ipFwNumber (struct variable *v, oid objid[], size_t *objid_len, 136 int exact, size_t *val_len, WriteMethod **write_method) 137{ 138 static int result; 139 struct route_table *table; 140 struct route_node *rn; 141 struct rib *rib; 142 143 if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) 144 return NULL; 145 146 table = vrf_table (AFI_IP, SAFI_UNICAST, 0); 147 if (! table) 148 return NULL; 149 150 /* Return number of routing entries. */ 151 result = 0; 152 for (rn = route_top (table); rn; rn = route_next (rn)) 153 RNODE_FOREACH_RIB (rn, rib) 154 result++; 155 156 return (u_char *)&result; 157} 158 159static u_char * 160ipCidrNumber (struct variable *v, oid objid[], size_t *objid_len, 161 int exact, size_t *val_len, WriteMethod **write_method) 162{ 163 static int result; 164 struct route_table *table; 165 struct route_node *rn; 166 struct rib *rib; 167 168 if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) 169 return NULL; 170 171 table = vrf_table (AFI_IP, SAFI_UNICAST, 0); 172 if (! table) 173 return 0; 174 175 /* Return number of routing entries. */ 176 result = 0; 177 for (rn = route_top (table); rn; rn = route_next (rn)) 178 RNODE_FOREACH_RIB (rn, rib) 179 result++; 180 181 return (u_char *)&result; 182} 183 184static int 185in_addr_cmp(u_char *p1, u_char *p2) 186{ 187 int i; 188 189 for (i=0; i<4; i++) 190 { 191 if (*p1 < *p2) 192 return -1; 193 if (*p1 > *p2) 194 return 1; 195 p1++; p2++; 196 } 197 return 0; 198} 199 200static int 201in_addr_add(u_char *p, int num) 202{ 203 int i, ip0; 204 205 ip0 = *p; 206 p += 4; 207 for (i = 3; 0 <= i; i--) { 208 p--; 209 if (*p + num > 255) { 210 *p += num; 211 num = 1; 212 } else { 213 *p += num; 214 return 1; 215 } 216 } 217 if (ip0 > *p) { 218 /* ip + num > 0xffffffff */ 219 return 0; 220 } 221 222 return 1; 223} 224 225static int 226proto_trans(int type) 227{ 228 switch (type) 229 { 230 case ZEBRA_ROUTE_SYSTEM: 231 return 1; /* other */ 232 case ZEBRA_ROUTE_KERNEL: 233 return 1; /* other */ 234 case ZEBRA_ROUTE_CONNECT: 235 return 2; /* local interface */ 236 case ZEBRA_ROUTE_STATIC: 237 return 3; /* static route */ 238 case ZEBRA_ROUTE_RIP: 239 return 8; /* rip */ 240 case ZEBRA_ROUTE_RIPNG: 241 return 1; /* shouldn't happen */ 242 case ZEBRA_ROUTE_OSPF: 243 return 13; /* ospf */ 244 case ZEBRA_ROUTE_OSPF6: 245 return 1; /* shouldn't happen */ 246 case ZEBRA_ROUTE_BGP: 247 return 14; /* bgp */ 248 default: 249 return 1; /* other */ 250 } 251} 252 253static void 254check_replace(struct route_node *np2, struct rib *rib2, 255 struct route_node **np, struct rib **rib) 256{ 257 int proto, proto2; 258 259 if (!*np) 260 { 261 *np = np2; 262 *rib = rib2; 263 return; 264 } 265 266 if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) < 0) 267 return; 268 if (in_addr_cmp(&(*np)->p.u.prefix, &np2->p.u.prefix) > 0) 269 { 270 *np = np2; 271 *rib = rib2; 272 return; 273 } 274 275 proto = proto_trans((*rib)->type); 276 proto2 = proto_trans(rib2->type); 277 278 if (proto2 > proto) 279 return; 280 if (proto2 < proto) 281 { 282 *np = np2; 283 *rib = rib2; 284 return; 285 } 286 287 if (in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4, 288 (u_char *)&rib2->nexthop->gate.ipv4) <= 0) 289 return; 290 291 *np = np2; 292 *rib = rib2; 293 return; 294} 295 296static void 297get_fwtable_route_node(struct variable *v, oid objid[], size_t *objid_len, 298 int exact, struct route_node **np, struct rib **rib) 299{ 300 struct in_addr dest; 301 struct route_table *table; 302 struct route_node *np2; 303 struct rib *rib2; 304 int proto; 305 int policy; 306 struct in_addr nexthop; 307 u_char *pnt; 308 int i; 309 310 /* Init index variables */ 311 312 pnt = (u_char *) &dest; 313 for (i = 0; i < 4; i++) 314 *pnt++ = 0; 315 316 pnt = (u_char *) &nexthop; 317 for (i = 0; i < 4; i++) 318 *pnt++ = 0; 319 320 proto = 0; 321 policy = 0; 322 323 /* Init return variables */ 324 325 *np = NULL; 326 *rib = NULL; 327 328 /* Short circuit exact matches of wrong length */ 329 330 if (exact && (*objid_len != (unsigned) v->namelen + 10)) 331 return; 332 333 table = vrf_table (AFI_IP, SAFI_UNICAST, 0); 334 if (! table) 335 return; 336 337 /* Get INDEX information out of OID. 338 * ipForwardDest, ipForwardProto, ipForwardPolicy, ipForwardNextHop 339 */ 340 341 if (*objid_len > (unsigned) v->namelen) 342 oid2in_addr (objid + v->namelen, MIN(4, *objid_len - v->namelen), &dest); 343 344 if (*objid_len > (unsigned) v->namelen + 4) 345 proto = objid[v->namelen + 4]; 346 347 if (*objid_len > (unsigned) v->namelen + 5) 348 policy = objid[v->namelen + 5]; 349 350 if (*objid_len > (unsigned) v->namelen + 6) 351 oid2in_addr (objid + v->namelen + 6, MIN(4, *objid_len - v->namelen - 6), 352 &nexthop); 353 354 /* Apply GETNEXT on not exact search */ 355 356 if (!exact && (*objid_len >= (unsigned) v->namelen + 10)) 357 { 358 if (! in_addr_add((u_char *) &nexthop, 1)) 359 return; 360 } 361 362 /* For exact: search matching entry in rib table. */ 363 364 if (exact) 365 { 366 if (policy) /* Not supported (yet?) */ 367 return; 368 for (*np = route_top (table); *np; *np = route_next (*np)) 369 { 370 if (!in_addr_cmp(&(*np)->p.u.prefix, (u_char *)&dest)) 371 { 372 RNODE_FOREACH_RIB (*np, *rib) 373 { 374 if (!in_addr_cmp((u_char *)&(*rib)->nexthop->gate.ipv4, 375 (u_char *)&nexthop)) 376 if (proto == proto_trans((*rib)->type)) 377 return; 378 } 379 } 380 } 381 return; 382 } 383 384 /* Search next best entry */ 385 386 for (np2 = route_top (table); np2; np2 = route_next (np2)) 387 { 388 389 /* Check destination first */ 390 if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) > 0) 391 RNODE_FOREACH_RIB (np2, rib2) 392 check_replace(np2, rib2, np, rib); 393 394 if (in_addr_cmp(&np2->p.u.prefix, (u_char *)&dest) == 0) 395 { /* have to look at each rib individually */ 396 RNODE_FOREACH_RIB (np2, rib2) 397 { 398 int proto2, policy2; 399 400 proto2 = proto_trans(rib2->type); 401 policy2 = 0; 402 403 if ((policy < policy2) 404 || ((policy == policy2) && (proto < proto2)) 405 || ((policy == policy2) && (proto == proto2) 406 && (in_addr_cmp((u_char *)&rib2->nexthop->gate.ipv4, 407 (u_char *) &nexthop) >= 0) 408 )) 409 check_replace(np2, rib2, np, rib); 410 } 411 } 412 } 413 414 if (!*rib) 415 return; 416 417 policy = 0; 418 proto = proto_trans((*rib)->type); 419 420 *objid_len = v->namelen + 10; 421 pnt = (u_char *) &(*np)->p.u.prefix; 422 for (i = 0; i < 4; i++) 423 objid[v->namelen + i] = *pnt++; 424 425 objid[v->namelen + 4] = proto; 426 objid[v->namelen + 5] = policy; 427 428 { 429 struct nexthop *nexthop; 430 431 nexthop = (*rib)->nexthop; 432 if (nexthop) 433 { 434 pnt = (u_char *) &nexthop->gate.ipv4; 435 for (i = 0; i < 4; i++) 436 objid[i + v->namelen + 6] = *pnt++; 437 } 438 } 439 440 return; 441} 442 443static u_char * 444ipFwTable (struct variable *v, oid objid[], size_t *objid_len, 445 int exact, size_t *val_len, WriteMethod **write_method) 446{ 447 struct route_node *np; 448 struct rib *rib; 449 static int result; 450 static int resarr[2]; 451 static struct in_addr netmask; 452 struct nexthop *nexthop; 453 454 if (smux_header_table(v, objid, objid_len, exact, val_len, write_method) 455 == MATCH_FAILED) 456 return NULL; 457 458 get_fwtable_route_node(v, objid, objid_len, exact, &np, &rib); 459 if (!np) 460 return NULL; 461 462 nexthop = rib->nexthop; 463 if (! nexthop) 464 return NULL; 465 466 switch (v->magic) 467 { 468 case IPFORWARDDEST: 469 *val_len = 4; 470 return &np->p.u.prefix; 471 break; 472 case IPFORWARDMASK: 473 masklen2ip(np->p.prefixlen, &netmask); 474 *val_len = 4; 475 return (u_char *)&netmask; 476 break; 477 case IPFORWARDPOLICY: 478 result = 0; 479 *val_len = sizeof(int); 480 return (u_char *)&result; 481 break; 482 case IPFORWARDNEXTHOP: 483 *val_len = 4; 484 return (u_char *)&nexthop->gate.ipv4; 485 break; 486 case IPFORWARDIFINDEX: 487 *val_len = sizeof(int); 488 return (u_char *)&nexthop->ifindex; 489 break; 490 case IPFORWARDTYPE: 491 if (nexthop->type == NEXTHOP_TYPE_IFINDEX 492 || nexthop->type == NEXTHOP_TYPE_IFNAME) 493 result = 3; 494 else 495 result = 4; 496 *val_len = sizeof(int); 497 return (u_char *)&result; 498 break; 499 case IPFORWARDPROTO: 500 result = proto_trans(rib->type); 501 *val_len = sizeof(int); 502 return (u_char *)&result; 503 break; 504 case IPFORWARDAGE: 505 result = 0; 506 *val_len = sizeof(int); 507 return (u_char *)&result; 508 break; 509 case IPFORWARDINFO: 510 resarr[0] = 0; 511 resarr[1] = 0; 512 *val_len = 2 * sizeof(int); 513 return (u_char *)resarr; 514 break; 515 case IPFORWARDNEXTHOPAS: 516 result = -1; 517 *val_len = sizeof(int); 518 return (u_char *)&result; 519 break; 520 case IPFORWARDMETRIC1: 521 result = 0; 522 *val_len = sizeof(int); 523 return (u_char *)&result; 524 break; 525 case IPFORWARDMETRIC2: 526 result = 0; 527 *val_len = sizeof(int); 528 return (u_char *)&result; 529 break; 530 case IPFORWARDMETRIC3: 531 result = 0; 532 *val_len = sizeof(int); 533 return (u_char *)&result; 534 break; 535 case IPFORWARDMETRIC4: 536 result = 0; 537 *val_len = sizeof(int); 538 return (u_char *)&result; 539 break; 540 case IPFORWARDMETRIC5: 541 result = 0; 542 *val_len = sizeof(int); 543 return (u_char *)&result; 544 break; 545 default: 546 return NULL; 547 break; 548 } 549 return NULL; 550} 551 552static u_char * 553ipCidrTable (struct variable *v, oid objid[], size_t *objid_len, 554 int exact, size_t *val_len, WriteMethod **write_method) 555{ 556 if (smux_header_table(v, objid, objid_len, exact, val_len, write_method) 557 == MATCH_FAILED) 558 return NULL; 559 560 switch (v->magic) 561 { 562 case IPCIDRROUTEDEST: 563 break; 564 default: 565 return NULL; 566 break; 567 } 568 return NULL; 569} 570 571void 572zebra_snmp_init () 573{ 574 smux_init (zebrad.master); 575 REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid); 576} 577#endif /* HAVE_SNMP */ 578