ripng_nexthop.c 5.7 KB

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