]>
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 | * | |
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 | ||
47 | struct ripng_rte_data { | |
48 | struct prefix_ipv6 *p; | |
49 | struct ripng_info *rinfo; | |
50 | struct ripng_aggregate *aggregate; | |
51 | }; | |
52 | ||
53 | void _ripng_rte_del(struct ripng_rte_data *A); | |
54 | int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B); | |
55 | ||
56 | #define METRIC_OUT(a) \ | |
fa40f658 | 57 | ((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)) | |
a94434b6 | 60 | #define TAG_OUT(a) \ |
fa40f658 | 61 | ((a)->rinfo ? (a)->rinfo->tag_out : (a)->aggregate->tag_out) |
a94434b6 | 62 | |
63 | struct list * | |
64 | ripng_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 | ||
74 | void | |
75 | ripng_rte_free(struct list *ripng_rte_list) { | |
76 | list_delete(ripng_rte_list); | |
77 | } | |
78 | ||
79 | /* Delete RTE */ | |
80 | void | |
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 | */ | |
90 | int | |
91 | _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) { | |
fa40f658 | 92 | return addr6_cmp(NEXTHOP_OUT_PTR(A), NEXTHOP_OUT_PTR(B)); |
a94434b6 | 93 | } |
94 | ||
95 | /* Add routing table entry */ | |
96 | void | |
97 | ripng_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 | */ | |
115 | void | |
116 | ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, | |
117 | struct sockaddr_in6 *to) { | |
118 | ||
119 | struct ripng_rte_data *data; | |
1eb8ef25 | 120 | struct listnode *node, *nnode; |
a94434b6 | 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, 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 | ||
1203e1c0 | 147 | mtu = ifp->mtu6; |
a94434b6 | 148 | 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 | ||
1eb8ef25 | 157 | for (ALL_LIST_ELEMENTS (ripng_rte_list, node, nnode, data)) { |
a94434b6 | 158 | /* (2.1) Next hop support */ |
fa40f658 | 159 | if (!IPV6_ADDR_SAME(&last_nexthop, NEXTHOP_OUT_PTR(data))) { |
a94434b6 | 160 | |
161 | /* A nexthop entry should be at least followed by 1 RTE */ | |
162 | if (num == (rtemax-1)) { | |
c9e52be3 | 163 | ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s), |
a94434b6 | 164 | 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 | */ | |
fa40f658 | 178 | if (!IN6_IS_ADDR_LINKLOCAL(NEXTHOP_OUT_PTR(data))) |
a94434b6 | 179 | last_nexthop = myself_nexthop; |
180 | else | |
fa40f658 | 181 | last_nexthop = *NEXTHOP_OUT_PTR(data); |
a94434b6 | 182 | |
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) { | |
c9e52be3 | 193 | ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s), |
a94434b6 | 194 | 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) { | |
c9e52be3 | 206 | ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s), |
a94434b6 | 207 | 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"); | |
a94434b6 | 212 | stream_reset (s); |
213 | } | |
214 | } |