]> git.proxmox.com Git - mirror_frr.git/blob - ripngd/ripng_nexthop.c
50972feffc9d5157ef69f22053df9a85de8b6a35
[mirror_frr.git] / ripngd / ripng_nexthop.c
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 along
17 * with this program; see the file COPYING; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
19 */
20
21 /* This file is required in order to support properly the RIPng nexthop
22 * feature.
23 */
24
25 #include <zebra.h>
26
27 /* For struct udphdr. */
28 #include <netinet/udp.h>
29
30 #include "linklist.h"
31 #include "stream.h"
32 #include "log.h"
33 #include "memory.h"
34 #include "vty.h"
35 #include "if.h"
36 #include "prefix.h"
37
38 #include "ripngd/ripngd.h"
39 #include "ripngd/ripng_debug.h"
40 #include "ripngd/ripng_nexthop.h"
41
42 DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data");
43
44 #define DEBUG 1
45
46 struct ripng_rte_data {
47 struct prefix_ipv6 *p;
48 struct ripng_info *rinfo;
49 struct ripng_aggregate *aggregate;
50 };
51
52 void _ripng_rte_del(struct ripng_rte_data *A);
53 int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B);
54
55 #define METRIC_OUT(a) \
56 ((a)->rinfo ? (a)->rinfo->metric_out : (a)->aggregate->metric_out)
57 #define NEXTHOP_OUT_PTR(a) \
58 ((a)->rinfo ? &((a)->rinfo->nexthop_out) \
59 : &((a)->aggregate->nexthop_out))
60 #define TAG_OUT(a) ((a)->rinfo ? (a)->rinfo->tag_out : (a)->aggregate->tag_out)
61
62 struct list *ripng_rte_new(void)
63 {
64 struct list *rte;
65
66 rte = list_new();
67 rte->cmp = (int (*)(void *, void *))_ripng_rte_cmp;
68 rte->del = (void (*)(void *))_ripng_rte_del;
69
70 return rte;
71 }
72
73 void ripng_rte_free(struct list *ripng_rte_list)
74 {
75 list_delete(&ripng_rte_list);
76 }
77
78 /* Delete RTE */
79 void _ripng_rte_del(struct ripng_rte_data *A)
80 {
81 XFREE(MTYPE_RIPNG_RTE_DATA, A);
82 }
83
84 /* Compare RTE:
85 * return + if A > B
86 * 0 if A = B
87 * - if A < B
88 */
89 int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B)
90 {
91 return addr6_cmp(NEXTHOP_OUT_PTR(A), NEXTHOP_OUT_PTR(B));
92 }
93
94 /* Add routing table entry */
95 void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p,
96 struct ripng_info *rinfo, struct ripng_aggregate *aggregate)
97 {
98
99 struct ripng_rte_data *data;
100
101 /* At least one should not be null */
102 assert(!rinfo || !aggregate);
103
104 data = XMALLOC(MTYPE_RIPNG_RTE_DATA, sizeof(*data));
105 data->p = p;
106 data->rinfo = rinfo;
107 data->aggregate = aggregate;
108
109 listnode_add_sort(ripng_rte_list, data);
110 }
111
112 /* Send the RTE with the nexthop support
113 */
114 void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp,
115 struct sockaddr_in6 *to)
116 {
117 struct ripng_interface *ri = ifp->info;
118 struct ripng *ripng = ri->ripng;
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,
135 * because
136 * we remain a right path without beeing the optimal one.
137 */
138 memset(&myself_nexthop, 0, sizeof(myself_nexthop));
139
140 /* Output stream get from ripng structre. XXX this should be
141 interface structure. */
142 s = ripng->obuf;
143
144 /* Reset stream and RTE counter. */
145 stream_reset(s);
146 num = 0;
147
148 mtu = ifp->mtu6;
149 if (mtu < 0)
150 mtu = IFMINMTU;
151
152 rtemax = (MIN(mtu, RIPNG_MAX_PACKET_SIZE) - IPV6_HDRLEN
153 - sizeof(struct udphdr) - sizeof(struct ripng_packet)
154 + sizeof(struct rte))
155 / 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 */
163 if (num == (rtemax - 1)) {
164 ret = ripng_send_packet((caddr_t)STREAM_DATA(s),
165 stream_get_endp(s), to,
166 ifp);
167
168 if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
169 ripng_packet_dump(
170 (struct ripng_packet *)
171 STREAM_DATA(s),
172 stream_get_endp(s), "SEND");
173 num = 0;
174 stream_reset(s);
175 }
176
177 /* Add the nexthop (2.1) */
178
179 /* If the received next hop address is not a link-local
180 * address,
181 * it should be treated as 0:0:0:0:0:0:0:0.
182 */
183 if (!IN6_IS_ADDR_LINKLOCAL(NEXTHOP_OUT_PTR(data)))
184 last_nexthop = myself_nexthop;
185 else
186 last_nexthop = *NEXTHOP_OUT_PTR(data);
187
188 num = ripng_write_rte(num, s, NULL, &last_nexthop, 0,
189 RIPNG_METRIC_NEXTHOP);
190 } else {
191 /* Rewrite the nexthop for each new packet */
192 if ((num == 0)
193 && !IPV6_ADDR_SAME(&last_nexthop, &myself_nexthop))
194 num = ripng_write_rte(num, s, NULL,
195 &last_nexthop, 0,
196 RIPNG_METRIC_NEXTHOP);
197 }
198 num = ripng_write_rte(num, s, data->p, NULL, TAG_OUT(data),
199 METRIC_OUT(data));
200
201 if (num == rtemax) {
202 ret = ripng_send_packet((caddr_t)STREAM_DATA(s),
203 stream_get_endp(s), to, ifp);
204
205 if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
206 ripng_packet_dump(
207 (struct ripng_packet *)STREAM_DATA(s),
208 stream_get_endp(s), "SEND");
209 num = 0;
210 stream_reset(s);
211 }
212 }
213
214 /* If unwritten RTE exist, flush it. */
215 if (num != 0) {
216 ret = ripng_send_packet((caddr_t)STREAM_DATA(s),
217 stream_get_endp(s), to, ifp);
218
219 if (ret >= 0 && IS_RIPNG_DEBUG_SEND)
220 ripng_packet_dump((struct ripng_packet *)STREAM_DATA(s),
221 stream_get_endp(s), "SEND");
222 stream_reset(s);
223 }
224 }