summaryrefslogtreecommitdiffstats
path: root/zebra/zebra_snmp.c
diff options
context:
space:
mode:
Diffstat (limited to 'zebra/zebra_snmp.c')
-rw-r--r--zebra/zebra_snmp.c556
1 files changed, 556 insertions, 0 deletions
diff --git a/zebra/zebra_snmp.c b/zebra/zebra_snmp.c
new file mode 100644
index 0000000..8cab184
--- /dev/null
+++ b/zebra/zebra_snmp.c
@@ -0,0 +1,556 @@
+// SPDX-License-Identifier: GPL-2.0-or-later
+/* FIB SNMP.
+ * Copyright (C) 1999 Kunihiro Ishiguro
+ */
+
+/*
+ * Currently SNMP is only running properly for MIBs in the default VRF.
+ */
+
+#include <zebra.h>
+
+#include <net-snmp/net-snmp-config.h>
+#include <net-snmp/net-snmp-includes.h>
+
+#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((uint8_t *)&(*np)->p.u.prefix4,
+ (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((uint8_t *)&np2->p.u.prefix4,
+ (uint8_t *)&dest) > 0)
+ RNODE_FOREACH_RE (np2, re2) {
+ check_replace(np2, re2, np, re);
+ }
+
+ if (in_addr_cmp((uint8_t *)&np2->p.u.prefix4, (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 event_loop *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,
+);