]>
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 | ||
42 | #define DEBUG 1 | |
43 | ||
44 | #define min(a, b) ((a) < (b) ? (a) : (b)) | |
45 | ||
46 | struct ripng_rte_data { | |
d62a17ae | 47 | struct prefix_ipv6 *p; |
48 | struct ripng_info *rinfo; | |
49 | struct ripng_aggregate *aggregate; | |
a94434b6 | 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 | ||
d62a17ae | 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) | |
a94434b6 | 61 | |
d62a17ae | 62 | struct list *ripng_rte_new(void) |
63 | { | |
64 | struct list *rte; | |
a94434b6 | 65 | |
d62a17ae | 66 | rte = list_new(); |
67 | rte->cmp = (int (*)(void *, void *))_ripng_rte_cmp; | |
68 | rte->del = (void (*)(void *))_ripng_rte_del; | |
a94434b6 | 69 | |
d62a17ae | 70 | return rte; |
a94434b6 | 71 | } |
72 | ||
d62a17ae | 73 | void ripng_rte_free(struct list *ripng_rte_list) |
74 | { | |
75 | list_delete(ripng_rte_list); | |
a94434b6 | 76 | } |
77 | ||
78 | /* Delete RTE */ | |
d62a17ae | 79 | void _ripng_rte_del(struct ripng_rte_data *A) |
80 | { | |
81 | XFREE(MTYPE_RIPNG_RTE_DATA, A); | |
a94434b6 | 82 | } |
83 | ||
84 | /* Compare RTE: | |
85 | * return + if A > B | |
86 | * 0 if A = B | |
87 | * - if A < B | |
88 | */ | |
d62a17ae | 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)); | |
a94434b6 | 92 | } |
93 | ||
94 | /* Add routing table entry */ | |
d62a17ae | 95 | void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p, |
96 | struct ripng_info *rinfo, struct ripng_aggregate *aggregate) | |
97 | { | |
a94434b6 | 98 | |
d62a17ae | 99 | struct ripng_rte_data *data; |
a94434b6 | 100 | |
d62a17ae | 101 | /* At least one should not be null */ |
102 | assert(!rinfo || !aggregate); | |
a94434b6 | 103 | |
d62a17ae | 104 | data = XMALLOC(MTYPE_RIPNG_RTE_DATA, sizeof(*data)); |
105 | data->p = p; | |
106 | data->rinfo = rinfo; | |
107 | data->aggregate = aggregate; | |
a94434b6 | 108 | |
d62a17ae | 109 | listnode_add_sort(ripng_rte_list, data); |
110 | } | |
a94434b6 | 111 | |
112 | /* Send the RTE with the nexthop support | |
113 | */ | |
d62a17ae | 114 | void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, |
115 | struct sockaddr_in6 *to) | |
116 | { | |
117 | ||
118 | struct ripng_rte_data *data; | |
119 | struct listnode *node, *nnode; | |
120 | ||
121 | struct in6_addr last_nexthop; | |
122 | struct in6_addr myself_nexthop; | |
123 | ||
124 | struct stream *s; | |
125 | int num; | |
126 | int mtu; | |
127 | int rtemax; | |
128 | int ret; | |
129 | ||
130 | /* Most of the time, there is no nexthop */ | |
131 | memset(&last_nexthop, 0, sizeof(last_nexthop)); | |
132 | ||
133 | /* Use myself_nexthop if the nexthop is not a link-local address, | |
134 | * 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) - IPV6_HDRLEN | |
152 | - sizeof(struct udphdr) - sizeof(struct ripng_packet) | |
153 | + sizeof(struct rte)) | |
154 | / sizeof(struct rte); | |
155 | ||
156 | for (ALL_LIST_ELEMENTS(ripng_rte_list, node, nnode, data)) { | |
157 | /* (2.1) Next hop support */ | |
158 | if (!IPV6_ADDR_SAME(&last_nexthop, NEXTHOP_OUT_PTR(data))) { | |
159 | ||
160 | /* A nexthop entry should be at least followed by 1 RTE | |
161 | */ | |
162 | if (num == (rtemax - 1)) { | |
163 | ret = ripng_send_packet((caddr_t)STREAM_DATA(s), | |
164 | stream_get_endp(s), to, | |
165 | ifp); | |
166 | ||
167 | if (ret >= 0 && IS_RIPNG_DEBUG_SEND) | |
168 | ripng_packet_dump( | |
169 | (struct ripng_packet *) | |
170 | STREAM_DATA(s), | |
171 | stream_get_endp(s), "SEND"); | |
172 | num = 0; | |
173 | stream_reset(s); | |
174 | } | |
175 | ||
176 | /* Add the nexthop (2.1) */ | |
177 | ||
178 | /* If the received next hop address is not a link-local | |
179 | * address, | |
180 | * it should be treated as 0:0:0:0:0:0:0:0. | |
181 | */ | |
182 | if (!IN6_IS_ADDR_LINKLOCAL(NEXTHOP_OUT_PTR(data))) | |
183 | last_nexthop = myself_nexthop; | |
184 | else | |
185 | last_nexthop = *NEXTHOP_OUT_PTR(data); | |
186 | ||
187 | num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, | |
188 | RIPNG_METRIC_NEXTHOP); | |
189 | } else { | |
190 | /* Rewrite the nexthop for each new packet */ | |
191 | if ((num == 0) | |
192 | && !IPV6_ADDR_SAME(&last_nexthop, &myself_nexthop)) | |
193 | num = ripng_write_rte(num, s, NULL, | |
194 | &last_nexthop, 0, | |
195 | RIPNG_METRIC_NEXTHOP); | |
196 | } | |
197 | num = ripng_write_rte(num, s, data->p, NULL, TAG_OUT(data), | |
198 | METRIC_OUT(data)); | |
199 | ||
200 | if (num == rtemax) { | |
201 | ret = ripng_send_packet((caddr_t)STREAM_DATA(s), | |
202 | stream_get_endp(s), to, ifp); | |
203 | ||
204 | if (ret >= 0 && IS_RIPNG_DEBUG_SEND) | |
205 | ripng_packet_dump( | |
206 | (struct ripng_packet *)STREAM_DATA(s), | |
207 | stream_get_endp(s), "SEND"); | |
208 | num = 0; | |
209 | stream_reset(s); | |
210 | } | |
211 | } | |
212 | ||
213 | /* If unwritten RTE exist, flush it. */ | |
214 | if (num != 0) { | |
215 | ret = ripng_send_packet((caddr_t)STREAM_DATA(s), | |
216 | stream_get_endp(s), to, ifp); | |
217 | ||
218 | if (ret >= 0 && IS_RIPNG_DEBUG_SEND) | |
219 | ripng_packet_dump((struct ripng_packet *)STREAM_DATA(s), | |
220 | stream_get_endp(s), "SEND"); | |
221 | stream_reset(s); | |
222 | } | |
a94434b6 | 223 | } |