]> git.proxmox.com Git - mirror_frr.git/blob - zebra/irdp_main.c
zebra, lib: error references for zebra
[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 "zebra_memory.h"
46 #include "stream.h"
47 #include "ioctl.h"
48 #include "connected.h"
49 #include "log.h"
50 #include "zclient.h"
51 #include "thread.h"
52 #include "privs.h"
53 #include "libfrr.h"
54 #include "lib_errors.h"
55 #include "version.h"
56 #include "zebra/interface.h"
57 #include "zebra/rtadv.h"
58 #include "zebra/rib.h"
59 #include "zebra/zserv.h"
60 #include "zebra/redistribute.h"
61 #include "zebra/irdp.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
69 /* GLOBAL VARS */
70
71 extern struct zebra_privs_t zserv_privs;
72
73 struct thread *t_irdp_raw;
74
75 /* Timer interval of irdp. */
76 int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
77
78 int irdp_sock_init(void)
79 {
80 int ret, i;
81 int save_errno;
82 int sock;
83
84 if (zserv_privs.change(ZPRIVS_RAISE))
85 zlog_ferr(LIB_ERR_PRIVILEGES,
86 "irdp_sock_init: could not raise privs, %s",
87 safe_strerror(errno));
88
89 sock = socket(AF_INET, SOCK_RAW, IPPROTO_ICMP);
90 save_errno = errno;
91
92 if (zserv_privs.change(ZPRIVS_LOWER))
93 zlog_ferr(LIB_ERR_PRIVILEGES,
94 "irdp_sock_init: could not lower privs, %s",
95 safe_strerror(errno));
96
97 if (sock < 0) {
98 zlog_warn("IRDP: can't create irdp socket %s",
99 safe_strerror(save_errno));
100 return sock;
101 };
102
103 i = 1;
104 ret = setsockopt(sock, IPPROTO_IP, IP_TTL, (void *)&i, sizeof(i));
105 if (ret < 0) {
106 zlog_warn("IRDP: can't do irdp sockopt %s",
107 safe_strerror(errno));
108 close(sock);
109 return ret;
110 };
111
112 ret = setsockopt_ifindex(AF_INET, sock, 1);
113 if (ret < 0) {
114 zlog_warn("IRDP: can't do irdp sockopt %s",
115 safe_strerror(errno));
116 close(sock);
117 return ret;
118 };
119
120 t_irdp_raw = NULL;
121 thread_add_read(zebrad.master, irdp_read_raw, NULL, sock, &t_irdp_raw);
122
123 return sock;
124 }
125
126
127 static int get_pref(struct irdp_interface *irdp, struct prefix *p)
128 {
129 struct listnode *node;
130 struct Adv *adv;
131
132 /* Use default preference or use the override pref */
133
134 if (irdp->AdvPrefList == NULL)
135 return irdp->Preference;
136
137 for (ALL_LIST_ELEMENTS_RO(irdp->AdvPrefList, node, adv))
138 if (p->u.prefix4.s_addr == adv->ip.s_addr)
139 return adv->pref;
140
141 return irdp->Preference;
142 }
143
144 /* Make ICMP Router Advertisement Message. */
145 static int make_advertisement_packet(struct interface *ifp, struct prefix *p,
146 struct stream *s)
147 {
148 struct zebra_if *zi = ifp->info;
149 struct irdp_interface *irdp = zi->irdp;
150 int size;
151 int pref;
152 uint16_t checksum;
153
154 pref = get_pref(irdp, p);
155
156 stream_putc(s, ICMP_ROUTERADVERT); /* Type. */
157 stream_putc(s, 0); /* Code. */
158 stream_putw(s, 0); /* Checksum. */
159 stream_putc(s, 1); /* Num address. */
160 stream_putc(s, 2); /* Address Entry Size. */
161
162 if (irdp->flags & IF_SHUTDOWN)
163 stream_putw(s, 0);
164 else
165 stream_putw(s, irdp->Lifetime);
166
167 stream_putl(s, htonl(p->u.prefix4.s_addr)); /* Router address. */
168 stream_putl(s, pref);
169
170 /* in_cksum return network byte order value */
171 size = 16;
172 checksum = in_cksum(s->data, size);
173 stream_putw_at(s, 2, htons(checksum));
174
175 return size;
176 }
177
178 static void irdp_send(struct interface *ifp, struct prefix *p, struct stream *s)
179 {
180 struct zebra_if *zi = ifp->info;
181 struct irdp_interface *irdp = zi->irdp;
182 char buf[PREFIX_STRLEN];
183 uint32_t dst;
184 uint32_t ttl = 1;
185
186 if (!irdp)
187 return;
188 if (!(ifp->flags & IFF_UP))
189 return;
190
191 if (irdp->flags & IF_BROADCAST)
192 dst = INADDR_BROADCAST;
193 else
194 dst = htonl(INADDR_ALLHOSTS_GROUP);
195
196 if (irdp->flags & IF_DEBUG_MESSAGES)
197 zlog_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d",
198 ifp->name, prefix2str(p, buf, sizeof buf),
199 irdp->flags & IF_SHUTDOWN ? 0 : irdp->Lifetime,
200 get_pref(irdp, p));
201
202 send_packet(ifp, s, dst, p, ttl);
203 }
204
205 static void irdp_advertisement(struct interface *ifp, struct prefix *p)
206 {
207 struct stream *s;
208 s = stream_new(128);
209 make_advertisement_packet(ifp, p, s);
210 irdp_send(ifp, p, s);
211 stream_free(s);
212 }
213
214 int irdp_send_thread(struct thread *t_advert)
215 {
216 uint32_t timer, tmp;
217 struct interface *ifp = THREAD_ARG(t_advert);
218 struct zebra_if *zi = ifp->info;
219 struct irdp_interface *irdp = zi->irdp;
220 struct prefix *p;
221 struct listnode *node, *nnode;
222 struct connected *ifc;
223
224 if (!irdp)
225 return 0;
226
227 irdp->flags &= ~IF_SOLICIT;
228
229 if (ifp->connected)
230 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
231 p = ifc->address;
232
233 if (p->family != AF_INET)
234 continue;
235
236 irdp_advertisement(ifp, p);
237 irdp->irdp_sent++;
238 }
239
240 tmp = irdp->MaxAdvertInterval - irdp->MinAdvertInterval;
241 timer = random() % (tmp + 1);
242 timer = irdp->MinAdvertInterval + timer;
243
244 if (irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS
245 && timer > MAX_INITIAL_ADVERT_INTERVAL)
246 timer = MAX_INITIAL_ADVERT_INTERVAL;
247
248 if (irdp->flags & IF_DEBUG_MISC)
249 zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name,
250 timer);
251
252 irdp->t_advertise = NULL;
253 thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer,
254 &irdp->t_advertise);
255 return 0;
256 }
257
258 void irdp_advert_off(struct interface *ifp)
259 {
260 struct zebra_if *zi = ifp->info;
261 struct irdp_interface *irdp = zi->irdp;
262 struct listnode *node, *nnode;
263 int i;
264 struct connected *ifc;
265 struct prefix *p;
266
267 if (!irdp)
268 return;
269
270 if (irdp->t_advertise)
271 thread_cancel(irdp->t_advertise);
272 irdp->t_advertise = NULL;
273
274 if (ifp->connected)
275 for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
276 p = ifc->address;
277
278 /* Output some packets with Lifetime 0
279 we should add a wait...
280 */
281
282 for (i = 0; i < IRDP_LAST_ADVERT_MESSAGES; i++) {
283 irdp->irdp_sent++;
284 irdp_advertisement(ifp, p);
285 }
286 }
287 }
288
289
290 void process_solicit(struct interface *ifp)
291 {
292 struct zebra_if *zi = ifp->info;
293 struct irdp_interface *irdp = zi->irdp;
294 uint32_t timer;
295
296 if (!irdp)
297 return;
298
299 /* When SOLICIT is active we reject further incoming solicits
300 this keeps down the answering rate so we don't have think
301 about DoS attacks here. */
302
303 if (irdp->flags & IF_SOLICIT)
304 return;
305
306 irdp->flags |= IF_SOLICIT;
307 if (irdp->t_advertise)
308 thread_cancel(irdp->t_advertise);
309 irdp->t_advertise = NULL;
310
311 timer = (random() % MAX_RESPONSE_DELAY) + 1;
312
313 irdp->t_advertise = NULL;
314 thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer,
315 &irdp->t_advertise);
316 }
317
318 static int irdp_finish(void)
319 {
320 struct vrf *vrf;
321 struct interface *ifp;
322 struct zebra_if *zi;
323 struct irdp_interface *irdp;
324
325 zlog_info("IRDP: Received shutdown notification.");
326
327 RB_FOREACH (vrf, vrf_id_head, &vrfs_by_id)
328 FOR_ALL_INTERFACES (vrf, ifp) {
329 zi = ifp->info;
330
331 if (!zi)
332 continue;
333 irdp = zi->irdp;
334 if (!irdp)
335 continue;
336
337 if (irdp->flags & IF_ACTIVE) {
338 irdp->flags |= IF_SHUTDOWN;
339 irdp_advert_off(ifp);
340 }
341 }
342 return 0;
343 }
344
345 static int irdp_init(struct thread_master *master)
346 {
347 irdp_if_init();
348
349 hook_register(frr_early_fini, irdp_finish);
350 return 0;
351 }
352
353 static int irdp_module_init(void)
354 {
355 hook_register(frr_late_init, irdp_init);
356 return 0;
357 }
358
359 FRR_MODULE_SETUP(.name = "zebra_irdp", .version = FRR_VERSION,
360 .description = "zebra IRDP module", .init = irdp_module_init, )