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