/* FIB SNMP. * Copyright (C) 1999 Kunihiro Ishiguro * * This file is part of GNU Zebra. * * GNU Zebra 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, or (at your option) any * later version. * * GNU Zebra 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; see the file COPYING; if not, write to the Free Software * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA */ /* * Currently SNMP is only running properly for MIBs in the default VRF. */ #include #include #include #include "if.h" #include "log.h" #include "prefix.h" #include "command.h" #include "smux.h" #include "table.h" #include "vrf.h" #include "hook.h" #include "libfrr.h" #include "lib/version.h" #include "zebra/rib.h" #include "zebra/zserv.h" #include "zebra/zebra_vrf.h" #define IPFWMIB 1,3,6,1,2,1,4,24 /* ipForwardTable */ #define IPFORWARDDEST 1 #define IPFORWARDMASK 2 #define IPFORWARDPOLICY 3 #define IPFORWARDNEXTHOP 4 #define IPFORWARDIFINDEX 5 #define IPFORWARDTYPE 6 #define IPFORWARDPROTO 7 #define IPFORWARDAGE 8 #define IPFORWARDINFO 9 #define IPFORWARDNEXTHOPAS 10 #define IPFORWARDMETRIC1 11 #define IPFORWARDMETRIC2 12 #define IPFORWARDMETRIC3 13 #define IPFORWARDMETRIC4 14 #define IPFORWARDMETRIC5 15 /* ipCidrRouteTable */ #define IPCIDRROUTEDEST 1 #define IPCIDRROUTEMASK 2 #define IPCIDRROUTETOS 3 #define IPCIDRROUTENEXTHOP 4 #define IPCIDRROUTEIFINDEX 5 #define IPCIDRROUTETYPE 6 #define IPCIDRROUTEPROTO 7 #define IPCIDRROUTEAGE 8 #define IPCIDRROUTEINFO 9 #define IPCIDRROUTENEXTHOPAS 10 #define IPCIDRROUTEMETRIC1 11 #define IPCIDRROUTEMETRIC2 12 #define IPCIDRROUTEMETRIC3 13 #define IPCIDRROUTEMETRIC4 14 #define IPCIDRROUTEMETRIC5 15 #define IPCIDRROUTESTATUS 16 #define INTEGER32 ASN_INTEGER #define GAUGE32 ASN_GAUGE #define ENUMERATION ASN_INTEGER #define ROWSTATUS ASN_INTEGER #define IPADDRESS ASN_IPADDRESS #define OBJECTIDENTIFIER ASN_OBJECT_ID static oid ipfw_oid[] = {IPFWMIB}; /* Hook functions. */ static uint8_t *ipFwNumber(struct variable *, oid[], size_t *, int, size_t *, WriteMethod **); static uint8_t *ipFwTable(struct variable *, oid[], size_t *, int, size_t *, WriteMethod **); static uint8_t *ipCidrNumber(struct variable *, oid[], size_t *, int, size_t *, WriteMethod **); static uint8_t *ipCidrTable(struct variable *, oid[], size_t *, int, size_t *, WriteMethod **); static struct variable zebra_variables[] = { {0, GAUGE32, RONLY, ipFwNumber, 1, {1}}, {IPFORWARDDEST, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 1}}, {IPFORWARDMASK, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 2}}, {IPFORWARDPOLICY, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 3}}, {IPFORWARDNEXTHOP, IPADDRESS, RONLY, ipFwTable, 3, {2, 1, 4}}, {IPFORWARDIFINDEX, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 5}}, {IPFORWARDTYPE, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 6}}, {IPFORWARDPROTO, ENUMERATION, RONLY, ipFwTable, 3, {2, 1, 7}}, {IPFORWARDAGE, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 8}}, {IPFORWARDINFO, OBJECTIDENTIFIER, RONLY, ipFwTable, 3, {2, 1, 9}}, {IPFORWARDNEXTHOPAS, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 10}}, {IPFORWARDMETRIC1, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 11}}, {IPFORWARDMETRIC2, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 12}}, {IPFORWARDMETRIC3, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 13}}, {IPFORWARDMETRIC4, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 14}}, {IPFORWARDMETRIC5, INTEGER32, RONLY, ipFwTable, 3, {2, 1, 15}}, {0, GAUGE32, RONLY, ipCidrNumber, 1, {3}}, {IPCIDRROUTEDEST, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 1}}, {IPCIDRROUTEMASK, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 2}}, {IPCIDRROUTETOS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 3}}, {IPCIDRROUTENEXTHOP, IPADDRESS, RONLY, ipCidrTable, 3, {4, 1, 4}}, {IPCIDRROUTEIFINDEX, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 5}}, {IPCIDRROUTETYPE, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 6}}, {IPCIDRROUTEPROTO, ENUMERATION, RONLY, ipCidrTable, 3, {4, 1, 7}}, {IPCIDRROUTEAGE, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 8}}, {IPCIDRROUTEINFO, OBJECTIDENTIFIER, RONLY, ipCidrTable, 3, {4, 1, 9}}, {IPCIDRROUTENEXTHOPAS, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 10}}, {IPCIDRROUTEMETRIC1, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 11}}, {IPCIDRROUTEMETRIC2, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 12}}, {IPCIDRROUTEMETRIC3, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 13}}, {IPCIDRROUTEMETRIC4, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 14}}, {IPCIDRROUTEMETRIC5, INTEGER32, RONLY, ipCidrTable, 3, {4, 1, 15}}, {IPCIDRROUTESTATUS, ROWSTATUS, RONLY, ipCidrTable, 3, {4, 1, 16}}}; static uint8_t *ipFwNumber(struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) { static int result; struct route_table *table; struct route_node *rn; struct route_entry *re; if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (!table) return NULL; /* Return number of routing entries. */ result = 0; for (rn = route_top(table); rn; rn = route_next(rn)) RNODE_FOREACH_RE (rn, re) { result++; } return (uint8_t *)&result; } static uint8_t *ipCidrNumber(struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) { static int result; struct route_table *table; struct route_node *rn; struct route_entry *re; if (smux_header_generic(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (!table) return 0; /* Return number of routing entries. */ result = 0; for (rn = route_top(table); rn; rn = route_next(rn)) RNODE_FOREACH_RE (rn, re) { result++; } return (uint8_t *)&result; } static int in_addr_cmp(uint8_t *p1, uint8_t *p2) { int i; for (i = 0; i < 4; i++) { if (*p1 < *p2) return -1; if (*p1 > *p2) return 1; p1++; p2++; } return 0; } static int in_addr_add(uint8_t *p, int num) { int i, ip0; ip0 = *p; p += 4; for (i = 3; 0 <= i; i--) { p--; if (*p + num > 255) { *p += num; num = 1; } else { *p += num; return 1; } } if (ip0 > *p) { /* ip + num > 0xffffffff */ return 0; } return 1; } static int proto_trans(int type) { switch (type) { case ZEBRA_ROUTE_SYSTEM: return 1; /* other */ case ZEBRA_ROUTE_KERNEL: return 1; /* other */ case ZEBRA_ROUTE_CONNECT: return 2; /* local interface */ case ZEBRA_ROUTE_STATIC: return 3; /* static route */ case ZEBRA_ROUTE_RIP: return 8; /* rip */ case ZEBRA_ROUTE_RIPNG: return 1; /* shouldn't happen */ case ZEBRA_ROUTE_OSPF: return 13; /* ospf */ case ZEBRA_ROUTE_OSPF6: return 1; /* shouldn't happen */ case ZEBRA_ROUTE_BGP: return 14; /* bgp */ default: return 1; /* other */ } } static void check_replace(struct route_node *np2, struct route_entry *re2, struct route_node **np, struct route_entry **re) { int proto, proto2; if (!*np) { *np = np2; *re = re2; return; } if (prefix_cmp(&(*np)->p, &np2->p) < 0) return; if (prefix_cmp(&(*np)->p, &np2->p) > 0) { *np = np2; *re = re2; return; } proto = proto_trans((*re)->type); proto2 = proto_trans(re2->type); if (proto2 > proto) return; if (proto2 < proto) { *np = np2; *re = re2; return; } if (in_addr_cmp((uint8_t *)&(*re)->nhe->nhg.nexthop->gate.ipv4, (uint8_t *)&re2->nhe->nhg.nexthop->gate.ipv4) <= 0) return; *np = np2; *re = re2; return; } static void get_fwtable_route_node(struct variable *v, oid objid[], size_t *objid_len, int exact, struct route_node **np, struct route_entry **re) { struct in_addr dest; struct route_table *table; struct route_node *np2; struct route_entry *re2; int proto; int policy; struct in_addr nexthop; uint8_t *pnt; int i; /* Init index variables */ pnt = (uint8_t *)&dest; for (i = 0; i < 4; i++) *pnt++ = 0; pnt = (uint8_t *)&nexthop; for (i = 0; i < 4; i++) *pnt++ = 0; proto = 0; policy = 0; /* Init return variables */ *np = NULL; *re = NULL; /* Short circuit exact matches of wrong length */ if (exact && (*objid_len != (unsigned)v->namelen + 10)) return; table = zebra_vrf_table(AFI_IP, SAFI_UNICAST, VRF_DEFAULT); if (!table) return; /* Get INDEX information out of OID. * ipForwardDest, ipForwardProto, ipForwardPolicy, ipForwardNextHop */ if (*objid_len > (unsigned)v->namelen) oid2in_addr(objid + v->namelen, MIN(4U, *objid_len - v->namelen), &dest); if (*objid_len > (unsigned)v->namelen + 4) proto = objid[v->namelen + 4]; if (*objid_len > (unsigned)v->namelen + 5) policy = objid[v->namelen + 5]; if (*objid_len > (unsigned)v->namelen + 6) oid2in_addr(objid + v->namelen + 6, MIN(4U, *objid_len - v->namelen - 6), &nexthop); /* Apply GETNEXT on not exact search */ if (!exact && (*objid_len >= (unsigned)v->namelen + 10)) { if (!in_addr_add((uint8_t *)&nexthop, 1)) return; } /* For exact: search matching entry in rib table. */ if (exact) { if (policy) /* Not supported (yet?) */ return; for (*np = route_top(table); *np; *np = route_next(*np)) { if (!in_addr_cmp(&(*np)->p.u.prefix, (uint8_t *)&dest)) { RNODE_FOREACH_RE (*np, *re) { if (!in_addr_cmp((uint8_t *)&(*re)->nhe ->nhg.nexthop ->gate.ipv4, (uint8_t *)&nexthop)) if (proto == proto_trans((*re)->type)) return; } } } return; } /* Search next best entry */ for (np2 = route_top(table); np2; np2 = route_next(np2)) { /* Check destination first */ if (in_addr_cmp(&np2->p.u.prefix, (uint8_t *)&dest) > 0) RNODE_FOREACH_RE (np2, re2) { check_replace(np2, re2, np, re); } if (in_addr_cmp(&np2->p.u.prefix, (uint8_t *)&dest) == 0) { /* have to look at each re individually */ RNODE_FOREACH_RE (np2, re2) { int proto2, policy2; proto2 = proto_trans(re2->type); policy2 = 0; if ((policy < policy2) || ((policy == policy2) && (proto < proto2)) || ((policy == policy2) && (proto == proto2) && (in_addr_cmp( (uint8_t *)&re2->nhe ->nhg.nexthop->gate.ipv4, (uint8_t *)&nexthop) >= 0))) check_replace(np2, re2, np, re); } } } if (!*re) return; policy = 0; proto = proto_trans((*re)->type); *objid_len = v->namelen + 10; pnt = (uint8_t *)&(*np)->p.u.prefix; for (i = 0; i < 4; i++) objid[v->namelen + i] = *pnt++; objid[v->namelen + 4] = proto; objid[v->namelen + 5] = policy; { struct nexthop *nexthop; nexthop = (*re)->nhe->nhg.nexthop; if (nexthop) { pnt = (uint8_t *)&nexthop->gate.ipv4; for (i = 0; i < 4; i++) objid[i + v->namelen + 6] = *pnt++; } } return; } static uint8_t *ipFwTable(struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) { struct route_node *np; struct route_entry *re; static int result; static int resarr[2]; static struct in_addr netmask; struct nexthop *nexthop; if (smux_header_table(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; get_fwtable_route_node(v, objid, objid_len, exact, &np, &re); if (!np) return NULL; nexthop = re->nhe->nhg.nexthop; if (!nexthop) return NULL; switch (v->magic) { case IPFORWARDDEST: *val_len = 4; return &np->p.u.prefix; case IPFORWARDMASK: masklen2ip(np->p.prefixlen, &netmask); *val_len = 4; return (uint8_t *)&netmask; case IPFORWARDPOLICY: result = 0; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDNEXTHOP: *val_len = 4; return (uint8_t *)&nexthop->gate.ipv4; case IPFORWARDIFINDEX: *val_len = sizeof(int); return (uint8_t *)&nexthop->ifindex; case IPFORWARDTYPE: if (nexthop->type == NEXTHOP_TYPE_IFINDEX) result = 3; else result = 4; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDPROTO: result = proto_trans(re->type); *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDAGE: result = 0; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDINFO: resarr[0] = 0; resarr[1] = 0; *val_len = 2 * sizeof(int); return (uint8_t *)resarr; case IPFORWARDNEXTHOPAS: result = -1; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC1: result = 0; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC2: result = 0; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC3: result = 0; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC4: result = 0; *val_len = sizeof(int); return (uint8_t *)&result; case IPFORWARDMETRIC5: result = 0; *val_len = sizeof(int); return (uint8_t *)&result; default: return NULL; } return NULL; } static uint8_t *ipCidrTable(struct variable *v, oid objid[], size_t *objid_len, int exact, size_t *val_len, WriteMethod **write_method) { if (smux_header_table(v, objid, objid_len, exact, val_len, write_method) == MATCH_FAILED) return NULL; switch (v->magic) { case IPCIDRROUTEDEST: break; default: return NULL; } return NULL; } static int zebra_snmp_init(struct thread_master *tm) { smux_init(tm); REGISTER_MIB("mibII/ipforward", zebra_variables, variable, ipfw_oid); return 0; } static int zebra_snmp_module_init(void) { hook_register(frr_late_init, zebra_snmp_init); return 0; } FRR_MODULE_SETUP(.name = "zebra_snmp", .version = FRR_VERSION, .description = "zebra AgentX SNMP module", .init = zebra_snmp_module_init, );