blob: 05f190e27b14017b527017df0ca0e5e811b51344 [file] [log] [blame]
hassoa94434b2003-05-25 17:10:12 +00001/* 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
47struct ripng_rte_data {
48 struct prefix_ipv6 *p;
49 struct ripng_info *rinfo;
50 struct ripng_aggregate *aggregate;
51};
52
53void _ripng_rte_del(struct ripng_rte_data *A);
54int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B);
55
56#define METRIC_OUT(a) \
ajsfa40f652004-12-16 16:18:13 +000057 ((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))
hassoa94434b2003-05-25 17:10:12 +000060#define TAG_OUT(a) \
ajsfa40f652004-12-16 16:18:13 +000061 ((a)->rinfo ? (a)->rinfo->tag_out : (a)->aggregate->tag_out)
hassoa94434b2003-05-25 17:10:12 +000062
63struct list *
64ripng_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
74void
75ripng_rte_free(struct list *ripng_rte_list) {
76 list_delete(ripng_rte_list);
77}
78
79/* Delete RTE */
80void
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 */
90int
91_ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) {
ajsfa40f652004-12-16 16:18:13 +000092 return addr6_cmp(NEXTHOP_OUT_PTR(A), NEXTHOP_OUT_PTR(B));
hassoa94434b2003-05-25 17:10:12 +000093}
94
95/* Add routing table entry */
96void
97ripng_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 */
115void
116ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp,
117 struct sockaddr_in6 *to) {
118
119 struct ripng_rte_data *data;
paul1eb8ef22005-04-07 07:30:20 +0000120 struct listnode *node, *nnode;
hassoa94434b2003-05-25 17:10:12 +0000121
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
hasso1203e1c2004-07-23 21:34:27 +0000147 mtu = ifp->mtu6;
hassoa94434b2003-05-25 17:10:12 +0000148 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
paul1eb8ef22005-04-07 07:30:20 +0000157 for (ALL_LIST_ELEMENTS (ripng_rte_list, node, nnode, data)) {
hassoa94434b2003-05-25 17:10:12 +0000158 /* (2.1) Next hop support */
ajsfa40f652004-12-16 16:18:13 +0000159 if (!IPV6_ADDR_SAME(&last_nexthop, NEXTHOP_OUT_PTR(data))) {
hassoa94434b2003-05-25 17:10:12 +0000160
161 /* A nexthop entry should be at least followed by 1 RTE */
162 if (num == (rtemax-1)) {
hassoc9e52be2004-09-26 16:09:34 +0000163 ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s),
hassoa94434b2003-05-25 17:10:12 +0000164 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 */
ajsfa40f652004-12-16 16:18:13 +0000178 if (!IN6_IS_ADDR_LINKLOCAL(NEXTHOP_OUT_PTR(data)))
hassoa94434b2003-05-25 17:10:12 +0000179 last_nexthop = myself_nexthop;
180 else
ajsfa40f652004-12-16 16:18:13 +0000181 last_nexthop = *NEXTHOP_OUT_PTR(data);
hassoa94434b2003-05-25 17:10:12 +0000182
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) {
hassoc9e52be2004-09-26 16:09:34 +0000193 ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s),
hassoa94434b2003-05-25 17:10:12 +0000194 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) {
hassoc9e52be2004-09-26 16:09:34 +0000206 ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s),
hassoa94434b2003-05-25 17:10:12 +0000207 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 num = 0;
213 stream_reset (s);
214 }
215}