Annotation of embedaddon/quagga/pimd/pim_zlookup.c, revision 1.1
1.1 ! misho 1: /*
! 2: PIM for Quagga
! 3: Copyright (C) 2008 Everton da Silva Marques
! 4:
! 5: This program is free software; you can redistribute it and/or modify
! 6: it under the terms of the GNU General Public License as published by
! 7: the Free Software Foundation; either version 2 of the License, or
! 8: (at your option) any later version.
! 9:
! 10: This program is distributed in the hope that it will be useful, but
! 11: WITHOUT ANY WARRANTY; without even the implied warranty of
! 12: MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
! 13: General Public License for more details.
! 14:
! 15: You should have received a copy of the GNU General Public License
! 16: along with this program; see the file COPYING; if not, write to the
! 17: Free Software Foundation, Inc., 51 Franklin St, Fifth Floor, Boston,
! 18: MA 02110-1301 USA
! 19:
! 20: $QuaggaId: $Format:%an, %ai, %h$ $
! 21: */
! 22:
! 23: #include <zebra.h>
! 24: #include "zebra/rib.h"
! 25:
! 26: #include "log.h"
! 27: #include "prefix.h"
! 28: #include "zclient.h"
! 29: #include "stream.h"
! 30: #include "network.h"
! 31: #include "thread.h"
! 32:
! 33: #include "pimd.h"
! 34: #include "pim_pim.h"
! 35: #include "pim_str.h"
! 36: #include "pim_zlookup.h"
! 37:
! 38: extern int zclient_debug;
! 39:
! 40: static void zclient_lookup_sched(struct zclient *zlookup, int delay);
! 41:
! 42: /* Connect to zebra for nexthop lookup. */
! 43: static int zclient_lookup_connect(struct thread *t)
! 44: {
! 45: struct zclient *zlookup;
! 46:
! 47: zlookup = THREAD_ARG(t);
! 48: zlookup->t_connect = NULL;
! 49:
! 50: if (zlookup->sock >= 0) {
! 51: return 0;
! 52: }
! 53:
! 54: if (zclient_socket_connect(zlookup) < 0) {
! 55: ++zlookup->fail;
! 56: zlog_warn("%s: failure connecting zclient socket: failures=%d",
! 57: __PRETTY_FUNCTION__, zlookup->fail);
! 58: }
! 59: else {
! 60: zlookup->fail = 0; /* reset counter on connection */
! 61: }
! 62:
! 63: zassert(!zlookup->t_connect);
! 64: if (zlookup->sock < 0) {
! 65: /* Since last connect failed, retry within 10 secs */
! 66: zclient_lookup_sched(zlookup, 10);
! 67: return -1;
! 68: }
! 69:
! 70: return 0;
! 71: }
! 72:
! 73: /* Schedule connection with delay. */
! 74: static void zclient_lookup_sched(struct zclient *zlookup, int delay)
! 75: {
! 76: zassert(!zlookup->t_connect);
! 77:
! 78: THREAD_TIMER_ON(master, zlookup->t_connect,
! 79: zclient_lookup_connect,
! 80: zlookup, delay);
! 81:
! 82: zlog_notice("%s: zclient lookup connection scheduled for %d seconds",
! 83: __PRETTY_FUNCTION__, delay);
! 84: }
! 85:
! 86: /* Schedule connection for now. */
! 87: static void zclient_lookup_sched_now(struct zclient *zlookup)
! 88: {
! 89: zassert(!zlookup->t_connect);
! 90:
! 91: zlookup->t_connect = thread_add_event(master, zclient_lookup_connect,
! 92: zlookup, 0);
! 93:
! 94: zlog_notice("%s: zclient lookup immediate connection scheduled",
! 95: __PRETTY_FUNCTION__);
! 96: }
! 97:
! 98: /* Schedule reconnection, if needed. */
! 99: static void zclient_lookup_reconnect(struct zclient *zlookup)
! 100: {
! 101: if (zlookup->t_connect) {
! 102: return;
! 103: }
! 104:
! 105: zclient_lookup_sched_now(zlookup);
! 106: }
! 107:
! 108: static void zclient_lookup_failed(struct zclient *zlookup)
! 109: {
! 110: if (zlookup->sock >= 0) {
! 111: if (close(zlookup->sock)) {
! 112: zlog_warn("%s: closing fd=%d: errno=%d %s", __func__, zlookup->sock,
! 113: errno, safe_strerror(errno));
! 114: }
! 115: zlookup->sock = -1;
! 116: }
! 117:
! 118: zclient_lookup_reconnect(zlookup);
! 119: }
! 120:
! 121: struct zclient *zclient_lookup_new()
! 122: {
! 123: struct zclient *zlookup;
! 124:
! 125: zlookup = zclient_new (master);
! 126: if (!zlookup) {
! 127: zlog_err("%s: zclient_new() failure",
! 128: __PRETTY_FUNCTION__);
! 129: return 0;
! 130: }
! 131:
! 132: zlookup->sock = -1;
! 133: zlookup->ibuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
! 134: zlookup->obuf = stream_new(ZEBRA_MAX_PACKET_SIZ);
! 135: zlookup->t_connect = 0;
! 136:
! 137: zclient_lookup_sched_now(zlookup);
! 138:
! 139: zlog_notice("%s: zclient lookup socket initialized",
! 140: __PRETTY_FUNCTION__);
! 141:
! 142: return zlookup;
! 143: }
! 144:
! 145: static int zclient_read_nexthop(struct zclient *zlookup,
! 146: struct pim_zlookup_nexthop nexthop_tab[],
! 147: const int tab_size,
! 148: struct in_addr addr)
! 149: {
! 150: int num_ifindex = 0;
! 151: struct stream *s;
! 152: const uint16_t MIN_LEN = 10; /* getipv4=4 getc=1 getl=4 getc=1 */
! 153: uint16_t length;
! 154: u_char marker;
! 155: u_char version;
! 156: uint16_t vrf_id;
! 157: uint16_t command;
! 158: int nbytes;
! 159: struct in_addr raddr;
! 160: uint8_t distance;
! 161: uint32_t metric;
! 162: int nexthop_num;
! 163: int i, err;
! 164:
! 165: if (PIM_DEBUG_ZEBRA) {
! 166: char addr_str[100];
! 167: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 168: zlog_debug("%s: addr=%s",
! 169: __PRETTY_FUNCTION__,
! 170: addr_str);
! 171: }
! 172:
! 173: s = zlookup->ibuf;
! 174: stream_reset(s);
! 175:
! 176: err = zclient_read_header (s, zlookup->sock, &length, &marker, &version,
! 177: &vrf_id, &command);
! 178: if (err < 0) {
! 179: zlog_err("%s %s: zclient_read_header() failed",
! 180: __FILE__, __PRETTY_FUNCTION__);
! 181: zclient_lookup_failed(zlookup);
! 182: return -1;
! 183: }
! 184:
! 185: if (length < MIN_LEN) {
! 186: zlog_err("%s %s: failure reading zclient lookup socket: len=%d < MIN_LEN=%d",
! 187: __FILE__, __PRETTY_FUNCTION__, length, MIN_LEN);
! 188: zclient_lookup_failed(zlookup);
! 189: return -2;
! 190: }
! 191:
! 192: nbytes = stream_read(s, zlookup->sock, length);
! 193: if (nbytes < length) {
! 194: zlog_err("%s %s: failure reading zclient lookup socket: nbytes=%d < len=%d",
! 195: __FILE__, __PRETTY_FUNCTION__, nbytes, length);
! 196: zclient_lookup_failed(zlookup);
! 197: return -3;
! 198: }
! 199:
! 200: if (command != ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB) {
! 201: zlog_err("%s: socket %d command mismatch: %d",
! 202: __func__, zlookup->sock, command);
! 203: return -5;
! 204: }
! 205:
! 206: raddr.s_addr = stream_get_ipv4(s);
! 207:
! 208: if (raddr.s_addr != addr.s_addr) {
! 209: char addr_str[100];
! 210: char raddr_str[100];
! 211: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 212: pim_inet4_dump("<raddr?>", raddr, raddr_str, sizeof(raddr_str));
! 213: zlog_warn("%s: address mismatch: addr=%s raddr=%s",
! 214: __PRETTY_FUNCTION__,
! 215: addr_str, raddr_str);
! 216: /* warning only */
! 217: }
! 218:
! 219: distance = stream_getc(s);
! 220: metric = stream_getl(s);
! 221: nexthop_num = stream_getc(s);
! 222:
! 223: if (nexthop_num < 1) {
! 224: zlog_err("%s: socket %d bad nexthop_num=%d",
! 225: __func__, zlookup->sock, nexthop_num);
! 226: return -6;
! 227: }
! 228:
! 229: length -= MIN_LEN;
! 230:
! 231: for (i = 0; i < nexthop_num; ++i) {
! 232: enum nexthop_types_t nexthop_type;
! 233:
! 234: if (length < 1) {
! 235: zlog_err("%s: socket %d empty input expecting nexthop_type: len=%d",
! 236: __func__, zlookup->sock, length);
! 237: return -7;
! 238: }
! 239:
! 240: nexthop_type = stream_getc(s);
! 241: --length;
! 242:
! 243: switch (nexthop_type) {
! 244: case ZEBRA_NEXTHOP_IFINDEX:
! 245: case ZEBRA_NEXTHOP_IFNAME:
! 246: case ZEBRA_NEXTHOP_IPV4_IFINDEX:
! 247: if (num_ifindex >= tab_size) {
! 248: char addr_str[100];
! 249: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 250: zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s",
! 251: __FILE__, __PRETTY_FUNCTION__,
! 252: (num_ifindex + 1), tab_size, addr_str);
! 253: return num_ifindex;
! 254: }
! 255: if (nexthop_type == ZEBRA_NEXTHOP_IPV4_IFINDEX) {
! 256: if (length < 4) {
! 257: zlog_err("%s: socket %d short input expecting nexthop IPv4-addr: len=%d",
! 258: __func__, zlookup->sock, length);
! 259: return -8;
! 260: }
! 261: nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s);
! 262: length -= 4;
! 263: }
! 264: else {
! 265: nexthop_tab[num_ifindex].nexthop_addr.s_addr = PIM_NET_INADDR_ANY;
! 266: }
! 267: nexthop_tab[num_ifindex].ifindex = stream_getl(s);
! 268: nexthop_tab[num_ifindex].protocol_distance = distance;
! 269: nexthop_tab[num_ifindex].route_metric = metric;
! 270: ++num_ifindex;
! 271: break;
! 272: case ZEBRA_NEXTHOP_IPV4:
! 273: if (num_ifindex >= tab_size) {
! 274: char addr_str[100];
! 275: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 276: zlog_warn("%s %s: found too many nexthop ifindexes (%d > %d) for address %s",
! 277: __FILE__, __PRETTY_FUNCTION__,
! 278: (num_ifindex + 1), tab_size, addr_str);
! 279: return num_ifindex;
! 280: }
! 281: nexthop_tab[num_ifindex].nexthop_addr.s_addr = stream_get_ipv4(s);
! 282: length -= 4;
! 283: nexthop_tab[num_ifindex].ifindex = 0;
! 284: nexthop_tab[num_ifindex].protocol_distance = distance;
! 285: nexthop_tab[num_ifindex].route_metric = metric;
! 286: if (PIM_DEBUG_ZEBRA) {
! 287: char addr_str[100];
! 288: char nexthop_str[100];
! 289: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 290: pim_inet4_dump("<nexthop?>", nexthop_tab[num_ifindex].nexthop_addr, nexthop_str, sizeof(nexthop_str));
! 291: zlog_debug("%s %s: zebra returned recursive nexthop %s for address %s",
! 292: __FILE__, __PRETTY_FUNCTION__,
! 293: nexthop_str, addr_str);
! 294: }
! 295: ++num_ifindex;
! 296: break;
! 297: default:
! 298: /* do nothing */
! 299: {
! 300: char addr_str[100];
! 301: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 302: zlog_warn("%s %s: found non-ifindex nexthop type=%d for address %s",
! 303: __FILE__, __PRETTY_FUNCTION__,
! 304: nexthop_type, addr_str);
! 305: }
! 306: break;
! 307: }
! 308: }
! 309:
! 310: return num_ifindex;
! 311: }
! 312:
! 313: static int zclient_lookup_nexthop_once(struct zclient *zlookup,
! 314: struct pim_zlookup_nexthop nexthop_tab[],
! 315: const int tab_size,
! 316: struct in_addr addr)
! 317: {
! 318: struct stream *s;
! 319: int ret;
! 320:
! 321: if (PIM_DEBUG_ZEBRA) {
! 322: char addr_str[100];
! 323: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 324: zlog_debug("%s: addr=%s",
! 325: __PRETTY_FUNCTION__,
! 326: addr_str);
! 327: }
! 328:
! 329: /* Check socket. */
! 330: if (zlookup->sock < 0) {
! 331: zlog_err("%s %s: zclient lookup socket is not connected",
! 332: __FILE__, __PRETTY_FUNCTION__);
! 333: zclient_lookup_failed(zlookup);
! 334: return -1;
! 335: }
! 336:
! 337: s = zlookup->obuf;
! 338: stream_reset(s);
! 339: zclient_create_header(s, ZEBRA_IPV4_NEXTHOP_LOOKUP_MRIB, VRF_DEFAULT);
! 340: stream_put_in_addr(s, &addr);
! 341: stream_putw_at(s, 0, stream_get_endp(s));
! 342:
! 343: ret = writen(zlookup->sock, s->data, stream_get_endp(s));
! 344: if (ret < 0) {
! 345: zlog_err("%s %s: writen() failure writing to zclient lookup socket",
! 346: __FILE__, __PRETTY_FUNCTION__);
! 347: zclient_lookup_failed(zlookup);
! 348: return -2;
! 349: }
! 350: if (ret == 0) {
! 351: zlog_err("%s %s: connection closed on zclient lookup socket",
! 352: __FILE__, __PRETTY_FUNCTION__);
! 353: zclient_lookup_failed(zlookup);
! 354: return -3;
! 355: }
! 356:
! 357: return zclient_read_nexthop(zlookup, nexthop_tab,
! 358: tab_size, addr);
! 359: }
! 360:
! 361: int zclient_lookup_nexthop(struct zclient *zlookup,
! 362: struct pim_zlookup_nexthop nexthop_tab[],
! 363: const int tab_size,
! 364: struct in_addr addr,
! 365: int max_lookup)
! 366: {
! 367: int lookup;
! 368: uint32_t route_metric = 0xFFFFFFFF;
! 369: uint8_t protocol_distance = 0xFF;
! 370:
! 371: for (lookup = 0; lookup < max_lookup; ++lookup) {
! 372: int num_ifindex;
! 373: int first_ifindex;
! 374: struct in_addr nexthop_addr;
! 375:
! 376: num_ifindex = zclient_lookup_nexthop_once(qpim_zclient_lookup, nexthop_tab,
! 377: PIM_NEXTHOP_IFINDEX_TAB_SIZE, addr);
! 378: if ((num_ifindex < 1) && PIM_DEBUG_ZEBRA) {
! 379: char addr_str[100];
! 380: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 381: zlog_warn("%s %s: lookup=%d/%d: could not find nexthop ifindex for address %s",
! 382: __FILE__, __PRETTY_FUNCTION__,
! 383: lookup, max_lookup, addr_str);
! 384: return -1;
! 385: }
! 386:
! 387: if (lookup < 1) {
! 388: /* this is the non-recursive lookup - save original metric/distance */
! 389: route_metric = nexthop_tab[0].route_metric;
! 390: protocol_distance = nexthop_tab[0].protocol_distance;
! 391: }
! 392:
! 393: /*
! 394: FIXME: Non-recursive nexthop ensured only for first ifindex.
! 395: However, recursive route lookup should really be fixed in zebra daemon.
! 396: See also TODO T24.
! 397: */
! 398: first_ifindex = nexthop_tab[0].ifindex;
! 399: nexthop_addr = nexthop_tab[0].nexthop_addr;
! 400: if (first_ifindex > 0) {
! 401: /* found: first ifindex is non-recursive nexthop */
! 402:
! 403: if ((lookup > 0) && PIM_DEBUG_ZEBRA) {
! 404: /* Report non-recursive success after first lookup */
! 405: char addr_str[100];
! 406: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 407: zlog_debug("%s %s: lookup=%d/%d: found non-recursive ifindex=%d for address %s dist=%d met=%d",
! 408: __FILE__, __PRETTY_FUNCTION__,
! 409: lookup, max_lookup, first_ifindex, addr_str,
! 410: nexthop_tab[0].protocol_distance,
! 411: nexthop_tab[0].route_metric);
! 412:
! 413: /* use last address as nexthop address */
! 414: nexthop_tab[0].nexthop_addr = addr;
! 415:
! 416: /* report original route metric/distance */
! 417: nexthop_tab[0].route_metric = route_metric;
! 418: nexthop_tab[0].protocol_distance = protocol_distance;
! 419: }
! 420:
! 421: return num_ifindex;
! 422: }
! 423:
! 424: if (PIM_DEBUG_ZEBRA) {
! 425: char addr_str[100];
! 426: char nexthop_str[100];
! 427: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 428: pim_inet4_dump("<nexthop?>", nexthop_addr, nexthop_str, sizeof(nexthop_str));
! 429: zlog_debug("%s %s: lookup=%d/%d: zebra returned recursive nexthop %s for address %s dist=%d met=%d",
! 430: __FILE__, __PRETTY_FUNCTION__,
! 431: lookup, max_lookup, nexthop_str, addr_str,
! 432: nexthop_tab[0].protocol_distance,
! 433: nexthop_tab[0].route_metric);
! 434: }
! 435:
! 436: addr = nexthop_addr; /* use nexthop addr for recursive lookup */
! 437:
! 438: } /* for (max_lookup) */
! 439:
! 440: if (PIM_DEBUG_ZEBRA) {
! 441: char addr_str[100];
! 442: pim_inet4_dump("<addr?>", addr, addr_str, sizeof(addr_str));
! 443: zlog_warn("%s %s: lookup=%d/%d: failure searching recursive nexthop ifindex for address %s",
! 444: __FILE__, __PRETTY_FUNCTION__,
! 445: lookup, max_lookup, addr_str);
! 446: }
! 447:
! 448: return -2;
! 449: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>