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

    1: /* RIPngd Zebra
    2:  * Copyright (C) 2002 6WIND <vincent.jardin@6wind.com>
    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: /* This file is required in order to support properly the RIPng nexthop
   23:  * feature.
   24:  */
   25: 
   26: #include <zebra.h>
   27: 
   28: /* For struct udphdr. */
   29: #include <netinet/udp.h>
   30: 
   31: #include "linklist.h"
   32: #include "stream.h"
   33: #include "log.h"
   34: #include "memory.h"
   35: #include "vty.h"
   36: #include "if.h"
   37: #include "prefix.h"
   38: 
   39: #include "ripngd/ripngd.h"
   40: #include "ripngd/ripng_debug.h"
   41: #include "ripngd/ripng_nexthop.h"
   42: 
   43: #define DEBUG 1
   44: 
   45: #define min(a, b) ((a) < (b) ? (a) : (b))
   46: 
   47: struct ripng_rte_data {
   48:   struct prefix_ipv6 *p;
   49:   struct ripng_info *rinfo;
   50:   struct ripng_aggregate *aggregate;
   51: };
   52: 
   53: void _ripng_rte_del(struct ripng_rte_data *A);
   54: int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B);
   55: 
   56: #define METRIC_OUT(a) \
   57:     ((a)->rinfo ?  (a)->rinfo->metric_out : (a)->aggregate->metric_out)
   58: #define NEXTHOP_OUT_PTR(a) \
   59:     ((a)->rinfo ?  &((a)->rinfo->nexthop_out) : &((a)->aggregate->nexthop_out))
   60: #define TAG_OUT(a) \
   61:     ((a)->rinfo ?  (a)->rinfo->tag_out : (a)->aggregate->tag_out)
   62: 
   63: struct list *
   64: ripng_rte_new(void) {
   65:   struct list *rte;
   66: 
   67:   rte = list_new();
   68:   rte->cmp = (int (*)(void *, void *)) _ripng_rte_cmp;
   69:   rte->del = (void (*)(void *)) _ripng_rte_del;
   70: 
   71:   return rte;
   72: }
   73: 
   74: void
   75: ripng_rte_free(struct list *ripng_rte_list) {
   76:   list_delete(ripng_rte_list);
   77: }
   78: 
   79: /* Delete RTE */
   80: void
   81: _ripng_rte_del(struct ripng_rte_data *A) {
   82:   XFREE(MTYPE_RIPNG_RTE_DATA, A);
   83: }
   84: 
   85: /* Compare RTE:
   86:  *  return +  if A > B
   87:  *         0  if A = B
   88:  *         -  if A < B
   89:  */
   90: int
   91: _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) {
   92:   return addr6_cmp(NEXTHOP_OUT_PTR(A), NEXTHOP_OUT_PTR(B));
   93: }
   94: 
   95: /* Add routing table entry */
   96: void
   97: ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p,
   98:               struct ripng_info *rinfo, struct ripng_aggregate *aggregate) {
   99: 
  100:   struct ripng_rte_data *data;
  101: 
  102:   /* At least one should not be null */
  103:   assert(!rinfo || !aggregate);
  104: 
  105:   data = XMALLOC(MTYPE_RIPNG_RTE_DATA, sizeof(*data));
  106:   data->p     = p;
  107:   data->rinfo = rinfo;
  108:   data->aggregate = aggregate;
  109: 
  110:   listnode_add_sort(ripng_rte_list, data);
  111: } 
  112: 
  113: /* Send the RTE with the nexthop support
  114:  */
  115: void
  116: ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp,
  117:                struct sockaddr_in6 *to) {
  118: 
  119:   struct ripng_rte_data *data;
  120:   struct listnode *node, *nnode;
  121: 
  122:   struct in6_addr last_nexthop;
  123:   struct in6_addr myself_nexthop;
  124: 
  125:   struct stream *s;
  126:   int num;
  127:   int mtu;
  128:   int rtemax;
  129:   int ret;
  130: 
  131:   /* Most of the time, there is no nexthop */
  132:   memset(&last_nexthop, 0, sizeof(last_nexthop));
  133: 
  134:   /* Use myself_nexthop if the nexthop is not a link-local address, because
  135:    * we remain a right path without beeing the optimal one.
  136:    */
  137:   memset(&myself_nexthop, 0, sizeof(myself_nexthop));
  138: 
  139:   /* Output stream get from ripng structre.  XXX this should be
  140:      interface structure. */
  141:   s = ripng->obuf;
  142: 
  143:   /* Reset stream and RTE counter. */
  144:   stream_reset (s);
  145:   num = 0;
  146: 
  147:   mtu = ifp->mtu6;
  148:   if (mtu < 0)
  149:     mtu = IFMINMTU;
  150: 
  151:   rtemax = (min (mtu, RIPNG_MAX_PACKET_SIZE) -
  152: 	    IPV6_HDRLEN - 
  153: 	    sizeof (struct udphdr) -
  154: 	    sizeof (struct ripng_packet) +
  155: 	    sizeof (struct rte)) / sizeof (struct rte);
  156: 
  157:   for (ALL_LIST_ELEMENTS (ripng_rte_list, node, nnode, data)) {
  158:     /* (2.1) Next hop support */
  159:     if (!IPV6_ADDR_SAME(&last_nexthop, NEXTHOP_OUT_PTR(data))) {
  160: 
  161:       /* A nexthop entry should be at least followed by 1 RTE */
  162:       if (num == (rtemax-1)) {
  163: 	ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s),
  164: 				 to, ifp);
  165: 
  166:         if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
  167:           ripng_packet_dump((struct ripng_packet *)STREAM_DATA (s),
  168: 			    stream_get_endp(s), "SEND");
  169:         num = 0;
  170:         stream_reset (s);
  171:       }
  172: 
  173:       /* Add the nexthop (2.1) */
  174: 
  175:       /* If the received next hop address is not a link-local address,
  176:        * it should be treated as 0:0:0:0:0:0:0:0.
  177:        */
  178:       if (!IN6_IS_ADDR_LINKLOCAL(NEXTHOP_OUT_PTR(data)))
  179:         last_nexthop = myself_nexthop;
  180:       else
  181: 	last_nexthop = *NEXTHOP_OUT_PTR(data);
  182: 
  183:       num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP);
  184:     } else {
  185:       /* Rewrite the nexthop for each new packet */
  186:       if ((num == 0) && !IPV6_ADDR_SAME(&last_nexthop, &myself_nexthop))
  187:         num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP);
  188:     }
  189:     num = ripng_write_rte(num, s, data->p, NULL,
  190: 			  TAG_OUT(data), METRIC_OUT(data));
  191: 
  192:     if (num == rtemax) {
  193:       ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s),
  194: 			       to, ifp);
  195: 
  196:       if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
  197:         ripng_packet_dump((struct ripng_packet *)STREAM_DATA (s),
  198: 			  stream_get_endp(s), "SEND");
  199:       num = 0;
  200:       stream_reset (s);
  201:     }
  202:   }
  203: 
  204:   /* If unwritten RTE exist, flush it. */
  205:   if (num != 0) {
  206:     ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s),
  207: 			     to, ifp);
  208: 
  209:     if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
  210:       ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s),
  211: 			 stream_get_endp (s), "SEND");
  212:     stream_reset (s);
  213:   }
  214: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>