]>
Commit | Line | Data |
---|---|---|
acddc0ed | 1 | // SPDX-License-Identifier: GPL-2.0-or-later |
a94434b6 | 2 | /* RIPngd Zebra |
3 | * Copyright (C) 2002 6WIND <vincent.jardin@6wind.com> | |
a94434b6 | 4 | */ |
5 | ||
6 | /* This file is required in order to support properly the RIPng nexthop | |
7 | * feature. | |
8 | */ | |
9 | ||
10 | #include <zebra.h> | |
11 | ||
12 | /* For struct udphdr. */ | |
13 | #include <netinet/udp.h> | |
14 | ||
15 | #include "linklist.h" | |
16 | #include "stream.h" | |
17 | #include "log.h" | |
18 | #include "memory.h" | |
19 | #include "vty.h" | |
20 | #include "if.h" | |
21 | #include "prefix.h" | |
22 | ||
23 | #include "ripngd/ripngd.h" | |
24 | #include "ripngd/ripng_debug.h" | |
25 | #include "ripngd/ripng_nexthop.h" | |
26 | ||
bf8d3d6a | 27 | DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data"); |
b3a7e30d | 28 | |
a94434b6 | 29 | #define DEBUG 1 |
30 | ||
a94434b6 | 31 | struct ripng_rte_data { |
d62a17ae | 32 | struct prefix_ipv6 *p; |
33 | struct ripng_info *rinfo; | |
34 | struct ripng_aggregate *aggregate; | |
a94434b6 | 35 | }; |
36 | ||
37 | void _ripng_rte_del(struct ripng_rte_data *A); | |
38 | int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B); | |
39 | ||
d62a17ae | 40 | #define METRIC_OUT(a) \ |
41 | ((a)->rinfo ? (a)->rinfo->metric_out : (a)->aggregate->metric_out) | |
42 | #define NEXTHOP_OUT_PTR(a) \ | |
43 | ((a)->rinfo ? &((a)->rinfo->nexthop_out) \ | |
44 | : &((a)->aggregate->nexthop_out)) | |
45 | #define TAG_OUT(a) ((a)->rinfo ? (a)->rinfo->tag_out : (a)->aggregate->tag_out) | |
a94434b6 | 46 | |
d62a17ae | 47 | struct list *ripng_rte_new(void) |
48 | { | |
49 | struct list *rte; | |
a94434b6 | 50 | |
d62a17ae | 51 | rte = list_new(); |
52 | rte->cmp = (int (*)(void *, void *))_ripng_rte_cmp; | |
53 | rte->del = (void (*)(void *))_ripng_rte_del; | |
a94434b6 | 54 | |
d62a17ae | 55 | return rte; |
a94434b6 | 56 | } |
57 | ||
d62a17ae | 58 | void ripng_rte_free(struct list *ripng_rte_list) |
59 | { | |
6a154c88 | 60 | list_delete(&ripng_rte_list); |
a94434b6 | 61 | } |
62 | ||
63 | /* Delete RTE */ | |
d62a17ae | 64 | void _ripng_rte_del(struct ripng_rte_data *A) |
65 | { | |
66 | XFREE(MTYPE_RIPNG_RTE_DATA, A); | |
a94434b6 | 67 | } |
68 | ||
69 | /* Compare RTE: | |
70 | * return + if A > B | |
71 | * 0 if A = B | |
72 | * - if A < B | |
73 | */ | |
d62a17ae | 74 | int _ripng_rte_cmp(struct ripng_rte_data *A, struct ripng_rte_data *B) |
75 | { | |
76 | return addr6_cmp(NEXTHOP_OUT_PTR(A), NEXTHOP_OUT_PTR(B)); | |
a94434b6 | 77 | } |
78 | ||
79 | /* Add routing table entry */ | |
d62a17ae | 80 | void ripng_rte_add(struct list *ripng_rte_list, struct prefix_ipv6 *p, |
81 | struct ripng_info *rinfo, struct ripng_aggregate *aggregate) | |
82 | { | |
a94434b6 | 83 | |
d62a17ae | 84 | struct ripng_rte_data *data; |
a94434b6 | 85 | |
d62a17ae | 86 | /* At least one should not be null */ |
87 | assert(!rinfo || !aggregate); | |
a94434b6 | 88 | |
d62a17ae | 89 | data = XMALLOC(MTYPE_RIPNG_RTE_DATA, sizeof(*data)); |
90 | data->p = p; | |
91 | data->rinfo = rinfo; | |
92 | data->aggregate = aggregate; | |
a94434b6 | 93 | |
d62a17ae | 94 | listnode_add_sort(ripng_rte_list, data); |
95 | } | |
a94434b6 | 96 | |
97 | /* Send the RTE with the nexthop support | |
98 | */ | |
d62a17ae | 99 | void ripng_rte_send(struct list *ripng_rte_list, struct interface *ifp, |
100 | struct sockaddr_in6 *to) | |
101 | { | |
5c84b9a5 RW |
102 | struct ripng_interface *ri = ifp->info; |
103 | struct ripng *ripng = ri->ripng; | |
d62a17ae | 104 | struct ripng_rte_data *data; |
105 | struct listnode *node, *nnode; | |
106 | ||
107 | struct in6_addr last_nexthop; | |
108 | struct in6_addr myself_nexthop; | |
109 | ||
110 | struct stream *s; | |
111 | int num; | |
112 | int mtu; | |
113 | int rtemax; | |
114 | int ret; | |
115 | ||
116 | /* Most of the time, there is no nexthop */ | |
117 | memset(&last_nexthop, 0, sizeof(last_nexthop)); | |
118 | ||
119 | /* Use myself_nexthop if the nexthop is not a link-local address, | |
120 | * because | |
121 | * we remain a right path without beeing the optimal one. | |
122 | */ | |
123 | memset(&myself_nexthop, 0, sizeof(myself_nexthop)); | |
124 | ||
125 | /* Output stream get from ripng structre. XXX this should be | |
126 | interface structure. */ | |
127 | s = ripng->obuf; | |
128 | ||
129 | /* Reset stream and RTE counter. */ | |
130 | stream_reset(s); | |
131 | num = 0; | |
132 | ||
133 | mtu = ifp->mtu6; | |
134 | if (mtu < 0) | |
135 | mtu = IFMINMTU; | |
136 | ||
7a8ce9d5 | 137 | rtemax = (MIN(mtu, RIPNG_MAX_PACKET_SIZE) - IPV6_HDRLEN |
d62a17ae | 138 | - sizeof(struct udphdr) - sizeof(struct ripng_packet) |
139 | + sizeof(struct rte)) | |
140 | / sizeof(struct rte); | |
141 | ||
142 | for (ALL_LIST_ELEMENTS(ripng_rte_list, node, nnode, data)) { | |
143 | /* (2.1) Next hop support */ | |
144 | if (!IPV6_ADDR_SAME(&last_nexthop, NEXTHOP_OUT_PTR(data))) { | |
145 | ||
146 | /* A nexthop entry should be at least followed by 1 RTE | |
147 | */ | |
148 | if (num == (rtemax - 1)) { | |
149 | ret = ripng_send_packet((caddr_t)STREAM_DATA(s), | |
150 | stream_get_endp(s), to, | |
151 | ifp); | |
152 | ||
153 | if (ret >= 0 && IS_RIPNG_DEBUG_SEND) | |
154 | ripng_packet_dump( | |
155 | (struct ripng_packet *) | |
156 | STREAM_DATA(s), | |
157 | stream_get_endp(s), "SEND"); | |
158 | num = 0; | |
159 | stream_reset(s); | |
160 | } | |
161 | ||
162 | /* Add the nexthop (2.1) */ | |
163 | ||
164 | /* If the received next hop address is not a link-local | |
165 | * address, | |
166 | * it should be treated as 0:0:0:0:0:0:0:0. | |
167 | */ | |
168 | if (!IN6_IS_ADDR_LINKLOCAL(NEXTHOP_OUT_PTR(data))) | |
169 | last_nexthop = myself_nexthop; | |
170 | else | |
171 | last_nexthop = *NEXTHOP_OUT_PTR(data); | |
172 | ||
173 | num = ripng_write_rte(num, s, NULL, &last_nexthop, 0, | |
174 | RIPNG_METRIC_NEXTHOP); | |
175 | } else { | |
176 | /* Rewrite the nexthop for each new packet */ | |
177 | if ((num == 0) | |
178 | && !IPV6_ADDR_SAME(&last_nexthop, &myself_nexthop)) | |
179 | num = ripng_write_rte(num, s, NULL, | |
180 | &last_nexthop, 0, | |
181 | RIPNG_METRIC_NEXTHOP); | |
182 | } | |
183 | num = ripng_write_rte(num, s, data->p, NULL, TAG_OUT(data), | |
184 | METRIC_OUT(data)); | |
185 | ||
186 | if (num == rtemax) { | |
187 | ret = ripng_send_packet((caddr_t)STREAM_DATA(s), | |
188 | stream_get_endp(s), to, ifp); | |
189 | ||
190 | if (ret >= 0 && IS_RIPNG_DEBUG_SEND) | |
191 | ripng_packet_dump( | |
192 | (struct ripng_packet *)STREAM_DATA(s), | |
193 | stream_get_endp(s), "SEND"); | |
194 | num = 0; | |
195 | stream_reset(s); | |
196 | } | |
197 | } | |
198 | ||
199 | /* If unwritten RTE exist, flush it. */ | |
200 | if (num != 0) { | |
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((struct ripng_packet *)STREAM_DATA(s), | |
206 | stream_get_endp(s), "SEND"); | |
207 | stream_reset(s); | |
208 | } | |
a94434b6 | 209 | } |