]> git.proxmox.com Git - mirror_frr.git/blob - zebra/irdp_main.c
pim6d: Add [no] ipv6 pim bsm" command
[mirror_frr.git] / zebra / irdp_main.c
1 /*
2 *
3 * Copyright (C) 2000 Robert Olsson.
4 * Swedish University of Agricultural Sciences
5 *
6 * This file is part of GNU Zebra.
7 *
8 * GNU Zebra is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; either version 2, or (at your option) any
11 * later version.
12 *
13 * GNU Zebra is distributed in the hope that it will be useful, but
14 * WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 * General Public License for more details.
17 *
18 * You should have received a copy of the GNU General Public License along
19 * with this program; see the file COPYING; if not, write to the Free Software
20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 */
22
23 /*
24 * This work includes work with the following copywrite:
25 *
26 * Copyright (C) 1997, 2000 Kunihiro Ishiguro
27 *
28 */
29
30 /*
31 * Thanks to Jens Laas at Swedish University of Agricultural Sciences
32 * for reviewing and tests.
33 */
34
35
36 #include <zebra.h>
37
38 #include "if.h"
39 #include "vty.h"
40 #include "sockunion.h"
41 #include "sockopt.h"
42 #include "prefix.h"
43 #include "command.h"
44 #include "memory.h"
45 #include "stream.h"
46 #include "ioctl.h"
47 #include "connected.h"
48 #include "log.h"
49 #include "zclient.h"
50 #include "thread.h"
51 #include "privs.h"
52 #include "libfrr.h"
53 #include "lib_errors.h"
54 #include "lib/version.h"
55 #include "zebra/interface.h"
56 #include "zebra/rtadv.h"
57 #include "zebra/rib.h"
58 #include "zebra/zebra_router.h"
59 #include "zebra/redistribute.h"
60 #include "zebra/irdp.h"
61 #include "zebra/zebra_errors.h"
62 #include <netinet/ip_icmp.h>
63
64 #include "checksum.h"
65 #include "if.h"
66 #include "sockunion.h"
67 #include "log.h"
68 #include "network.h"
69
70 /* GLOBAL VARS */
71
72 extern struct zebra_privs_t zserv_privs;
73
74 struct thread *t_irdp_raw;
75
76 /* Timer interval of irdp. */
77 int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
78
79 int irdp_sock_init(void)
80 {
81 int ret, i;
82 int save_errno;
83 int sock;
84
85 frr_with_privs(&zserv_privs) {
86
87 sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
88 save_errno = errno;
89
90 }
91
92 if (sock < 0) {
93 flog_err_sys(EC_LIB_SOCKET, "IRDP: can't create irdp socket %s",
94 safe_strerror(save_errno));
95 return sock;
96 };
97
98 i = 1;
99 ret = setsockopt(sock, IPPROTO_IP, IP_TTL, (void *)&i, sizeof(i));
100 if (ret < 0) {
101 flog_err_sys(EC_LIB_SOCKET, "IRDP: can't do irdp sockopt %s",
102 safe_strerror(errno));
103 close(sock);
104 return ret;
105 };
106
107 ret = setsockopt_ifindex(AF_INET, sock, 1);
108 if (ret < 0) {
109 flog_err_sys(EC_LIB_SOCKET, "IRDP: can't do irdp sockopt %s",
110 safe_strerror(errno));
111 close(sock);
112 return ret;
113 };
114
115 thread_add_read(zrouter.master, irdp_read_raw, NULL, sock, &t_irdp_raw);
116
117 return sock;
118 }
119
120
121 static int get_pref(struct irdp_interface *irdp, struct prefix *p)
122 {
123 struct listnode *node;
124 struct Adv *adv;
125
126 /* Use default preference or use the override pref */
127
128 if (irdp->AdvPrefList == NULL)
129 return irdp->Preference;
130
131 for (ALL_LIST_ELEMENTS_RO(irdp->AdvPrefList, node, adv))
132 if (p->u.prefix4.s_addr == adv->ip.s_addr)
133 return adv->pref;
134
135 return irdp->Preference;
136 }
137
138 /* Make ICMP Router Advertisement Message. */
139 static int make_advertisement_packet(struct interface *ifp, struct prefix *p,
140 struct stream *s)
141 {
142 struct zebra_if *zi = ifp->info;
143 struct irdp_interface *irdp = zi->irdp;
144 int size;
145 int pref;
146 uint16_t checksum;
147
148 pref = get_pref(irdp, p);
149
150 stream_putc(s, ICMP_ROUTERADVERT); /* Type. */
151 stream_putc(s, 0); /* Code. */
152 stream_putw(s, 0); /* Checksum. */
153 stream_putc(s, 1); /* Num address. */
154 stream_putc(s, 2); /* Address Entry Size. */
155
156 if (irdp->flags & IF_SHUTDOWN)
157 stream_putw(s, 0);
158 else
159 stream_putw(s, irdp->Lifetime);
160
161 stream_putl(s, htonl(p->u.prefix4.s_addr)); /* Router address. */
162 stream_putl(s, pref);
163
164 /* in_cksum return network byte order value */
165 size = 16;
166 checksum = in_cksum(s->data, size);
167 stream_putw_at(s, 2, htons(checksum));
168
169 return size;
170 }
171
172 static void irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
173 {
174 struct zebra_if *zi = ifp->info;
175 struct irdp_interface *irdp = zi->irdp;
176 uint32_t dst;
177 uint32_t ttl = 1;
178
179 if (!irdp)
180 return;
181 if (!(ifp->flags & IFF_UP))
182 return;
183
184 if (irdp->flags & IF_BROADCAST)
185 dst = INADDR_BROADCAST;
186 else
187 dst = htonl(INADDR_ALLHOSTS_GROUP);
188
189 if (irdp->flags & IF_DEBUG_MESSAGES)
190 zlog_debug(
191 "IRDP: TX Advert on %s %pFX Holdtime=%d Preference=%d",
192 ifp->name, p,
193 irdp->flags & IF_SHUTDOWN ? 0 : irdp->Lifetime,
194 get_pref(irdp, p));
195
196 send_packet(ifp, s, dst, p, ttl);
197 }
198
199 static void irdp_advertisement(struct interface *ifp, struct prefix *p)
200 {
201 struct stream *s;
202 s = stream_new(128);
203 make_advertisement_packet(ifp, p, s);
204 irdp_send(ifp, p, s);
205 stream_free(s);
206 }
207
208 void irdp_send_thread(struct thread *t_advert)
209 {
210 uint32_t timer, tmp;
211 struct interface *ifp = THREAD_ARG(t_advert);
212 struct zebra_if *zi = ifp->info;
213 struct irdp_interface *irdp = zi->irdp;
214 struct prefix *p;
215 struct listnode *node, *nnode;
216 struct connected *ifc;
217
218 if (!irdp)
219 return;
220
221 irdp->flags &= ~IF_SOLICIT;
222
223 if (ifp->connected)
224 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
225 p = ifc->address;
226
227 if (p->family != AF_INET)
228 continue;
229
230 irdp_advertisement(ifp, p);
231 irdp->irdp_sent++;
232 }
233
234 tmp = irdp->MaxAdvertInterval - irdp->MinAdvertInterval;
235 timer = frr_weak_random() % (tmp + 1);
236 timer = irdp->MinAdvertInterval + timer;
237
238 if (irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS
239 && timer > MAX_INITIAL_ADVERT_INTERVAL)
240 timer = MAX_INITIAL_ADVERT_INTERVAL;
241
242 if (irdp->flags & IF_DEBUG_MISC)
243 zlog_debug("IRDP: New timer for %s set to %u", ifp->name,
244 timer);
245
246 irdp->t_advertise = NULL;
247 thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer,
248 &irdp->t_advertise);
249 }
250
251 void irdp_advert_off(struct interface *ifp)
252 {
253 struct zebra_if *zi = ifp->info;
254 struct irdp_interface *irdp = zi->irdp;
255 struct listnode *node, *nnode;
256 int i;
257 struct connected *ifc;
258 struct prefix *p;
259
260 if (!irdp)
261 return;
262
263 THREAD_OFF(irdp->t_advertise);
264
265 if (ifp->connected)
266 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
267 p = ifc->address;
268
269 /* Output some packets with Lifetime 0
270 we should add a wait...
271 */
272
273 for (i = 0; i < IRDP_LAST_ADVERT_MESSAGES; i++) {
274 irdp->irdp_sent++;
275 irdp_advertisement(ifp, p);
276 }
277 }
278 }
279
280
281 void process_solicit(struct interface *ifp)
282 {
283 struct zebra_if *zi = ifp->info;
284 struct irdp_interface *irdp = zi->irdp;
285 uint32_t timer;
286
287 if (!irdp)
288 return;
289
290 /* When SOLICIT is active we reject further incoming solicits
291 this keeps down the answering rate so we don't have think
292 about DoS attacks here. */
293
294 if (irdp->flags & IF_SOLICIT)
295 return;
296
297 irdp->flags |= IF_SOLICIT;
298 THREAD_OFF(irdp->t_advertise);
299
300 timer = (frr_weak_random() % MAX_RESPONSE_DELAY) + 1;
301
302 irdp->t_advertise = NULL;
303 thread_add_timer(zrouter.master, irdp_send_thread, ifp, timer,
304 &irdp->t_advertise);
305 }
306
307 static int irdp_finish(void)
308 {
309 struct vrf *vrf;
310 struct interface *ifp;
311 struct zebra_if *zi;
312 struct irdp_interface *irdp;
313
314 zlog_info("IRDP: Received shutdown notification.");
315
316 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
317 FOR_ALL_INTERFACES (vrf, ifp) {
318 zi = ifp->info;
319
320 if (!zi)
321 continue;
322 irdp = zi->irdp;
323 if (!irdp)
324 continue;
325
326 if (irdp->flags & IF_ACTIVE) {
327 irdp->flags |= IF_SHUTDOWN;
328 irdp_advert_off(ifp);
329 }
330 }
331 return 0;
332 }
333
334 static int irdp_init(struct thread_master *master)
335 {
336 irdp_if_init();
337
338 hook_register(frr_early_fini, irdp_finish);
339 return 0;
340 }
341
342 static int irdp_module_init(void)
343 {
344 hook_register(frr_late_init, irdp_init);
345 return 0;
346 }
347
348 FRR_MODULE_SETUP(.name = "zebra_irdp", .version = FRR_VERSION,
349 .description = "zebra IRDP module", .init = irdp_module_init,
350 );