File:  [ELWIX - Embedded LightWeight unIX -] / embedaddon / quagga / pimd / pim_zlookup.c
Revision 1.1.1.1 (vendor branch): download - view: text, annotated - select for diffs - revision graph
Wed Nov 2 10:09:11 2016 UTC (7 years, 7 months ago) by misho
Branches: quagga, MAIN
CVS tags: v1_0_20160315, HEAD
quagga 1.0.20160315

    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>