]> git.proxmox.com Git - mirror_frr.git/blame - ripngd/ripng_nexthop.c
*: auto-convert to SPDX License IDs
[mirror_frr.git] / ripngd / ripng_nexthop.c
CommitLineData
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 27DEFINE_MTYPE_STATIC(RIPNGD, RIPNG_RTE_DATA, "RIPng rte data");
b3a7e30d 28
a94434b6 29#define DEBUG 1
30
a94434b6 31struct ripng_rte_data {
d62a17ae 32 struct prefix_ipv6 *p;
33 struct ripng_info *rinfo;
34 struct ripng_aggregate *aggregate;
a94434b6 35};
36
37void _ripng_rte_del(struct ripng_rte_data *A);
38int _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 47struct 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 58void ripng_rte_free(struct list *ripng_rte_list)
59{
6a154c88 60 list_delete(&ripng_rte_list);
a94434b6 61}
62
63/* Delete RTE */
d62a17ae 64void _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 74int _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 80void 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 99void 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}