]>
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 { | |
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) \ | |
fa40f658 | 56 | ((a)->rinfo ? (a)->rinfo->metric_out : (a)->aggregate->metric_out) |
57 | #define NEXTHOP_OUT_PTR(a) \ | |
58 | ((a)->rinfo ? &((a)->rinfo->nexthop_out) : &((a)->aggregate->nexthop_out)) | |
a94434b6 | 59 | #define TAG_OUT(a) \ |
fa40f658 | 60 | ((a)->rinfo ? (a)->rinfo->tag_out : (a)->aggregate->tag_out) |
a94434b6 | 61 | |
62 | struct list * | |
63 | ripng_rte_new(void) { | |
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 | |
74 | ripng_rte_free(struct list *ripng_rte_list) { | |
75 | list_delete(ripng_rte_list); | |
76 | } | |
77 | ||
78 | /* Delete RTE */ | |
79 | void | |
80 | _ripng_rte_del(struct ripng_rte_data *A) { | |
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 | |
90 | _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) { | |
fa40f658 | 91 | return addr6_cmp(NEXTHOP_OUT_PTR(A), NEXTHOP_OUT_PTR(B)); |
a94434b6 | 92 | } |
93 | ||
94 | /* Add routing table entry */ | |
95 | void | |
96 | ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p, | |
97 | struct ripng_info *rinfo, struct ripng_aggregate *aggregate) { | |
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 | |
115 | ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, | |
116 | struct sockaddr_in6 *to) { | |
117 | ||
118 | struct ripng_rte_data *data; | |
1eb8ef25 | 119 | struct listnode *node, *nnode; |
a94434b6 | 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, because | |
134 | * we remain a right path without beeing the optimal one. | |
135 | */ | |
136 | memset(&myself_nexthop, 0, sizeof(myself_nexthop)); | |
137 | ||
138 | /* Output stream get from ripng structre. XXX this should be | |
139 | interface structure. */ | |
140 | s = ripng->obuf; | |
141 | ||
142 | /* Reset stream and RTE counter. */ | |
143 | stream_reset (s); | |
144 | num = 0; | |
145 | ||
1203e1c0 | 146 | mtu = ifp->mtu6; |
a94434b6 | 147 | if (mtu < 0) |
148 | mtu = IFMINMTU; | |
149 | ||
150 | rtemax = (min (mtu, RIPNG_MAX_PACKET_SIZE) - | |
151 | IPV6_HDRLEN - | |
152 | sizeof (struct udphdr) - | |
153 | sizeof (struct ripng_packet) + | |
154 | sizeof (struct rte)) / sizeof (struct rte); | |
155 | ||
1eb8ef25 | 156 | for (ALL_LIST_ELEMENTS (ripng_rte_list, node, nnode, data)) { |
a94434b6 | 157 | /* (2.1) Next hop support */ |
fa40f658 | 158 | if (!IPV6_ADDR_SAME(&last_nexthop, NEXTHOP_OUT_PTR(data))) { |
a94434b6 | 159 | |
160 | /* A nexthop entry should be at least followed by 1 RTE */ | |
161 | if (num == (rtemax-1)) { | |
c9e52be3 | 162 | ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s), |
a94434b6 | 163 | to, ifp); |
164 | ||
165 | if (ret >= 0 && IS_RIPNG_DEBUG_SEND) | |
166 | ripng_packet_dump((struct ripng_packet *)STREAM_DATA (s), | |
167 | stream_get_endp(s), "SEND"); | |
168 | num = 0; | |
169 | stream_reset (s); | |
170 | } | |
171 | ||
172 | /* Add the nexthop (2.1) */ | |
173 | ||
174 | /* If the received next hop address is not a link-local address, | |
175 | * it should be treated as 0:0:0:0:0:0:0:0. | |
176 | */ | |
fa40f658 | 177 | if (!IN6_IS_ADDR_LINKLOCAL(NEXTHOP_OUT_PTR(data))) |
a94434b6 | 178 | last_nexthop = myself_nexthop; |
179 | else | |
fa40f658 | 180 | last_nexthop = *NEXTHOP_OUT_PTR(data); |
a94434b6 | 181 | |
182 | num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP); | |
183 | } else { | |
184 | /* Rewrite the nexthop for each new packet */ | |
185 | if ((num == 0) && !IPV6_ADDR_SAME(&last_nexthop, &myself_nexthop)) | |
186 | num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, RIPNG_METRIC_NEXTHOP); | |
187 | } | |
188 | num = ripng_write_rte(num, s, data->p, NULL, | |
189 | TAG_OUT(data), METRIC_OUT(data)); | |
190 | ||
191 | if (num == rtemax) { | |
c9e52be3 | 192 | ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s), |
a94434b6 | 193 | to, ifp); |
194 | ||
195 | if (ret >= 0 && IS_RIPNG_DEBUG_SEND) | |
196 | ripng_packet_dump((struct ripng_packet *)STREAM_DATA (s), | |
197 | stream_get_endp(s), "SEND"); | |
198 | num = 0; | |
199 | stream_reset (s); | |
200 | } | |
201 | } | |
202 | ||
203 | /* If unwritten RTE exist, flush it. */ | |
204 | if (num != 0) { | |
c9e52be3 | 205 | ret = ripng_send_packet ((caddr_t) STREAM_DATA (s), stream_get_endp (s), |
a94434b6 | 206 | to, ifp); |
207 | ||
208 | if (ret >= 0 && IS_RIPNG_DEBUG_SEND) | |
209 | ripng_packet_dump ((struct ripng_packet *)STREAM_DATA (s), | |
210 | stream_get_endp (s), "SEND"); | |
a94434b6 | 211 | stream_reset (s); |
212 | } | |
213 | } |