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