]> git.proxmox.com Git - mirror_frr.git/blob - zebra/irdp_main.c
Merge pull request #735 from qlyoung/fix-routemap
[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 Låås at Swedish University of Agricultural Sciences
32 * for reviewing and tests.
33 */
34
35
36 #include <zebra.h>
37
38 #ifdef HAVE_IRDP
39
40 #include "if.h"
41 #include "vty.h"
42 #include "sockunion.h"
43 #include "sockopt.h"
44 #include "prefix.h"
45 #include "command.h"
46 #include "memory.h"
47 #include "zebra_memory.h"
48 #include "stream.h"
49 #include "ioctl.h"
50 #include "connected.h"
51 #include "log.h"
52 #include "zclient.h"
53 #include "thread.h"
54 #include "privs.h"
55 #include "zebra/interface.h"
56 #include "zebra/rtadv.h"
57 #include "zebra/rib.h"
58 #include "zebra/zserv.h"
59 #include "zebra/redistribute.h"
60 #include "zebra/irdp.h"
61 #include <netinet/ip_icmp.h>
62
63 #include "checksum.h"
64 #include "if.h"
65 #include "sockunion.h"
66 #include "log.h"
67
68 /* GLOBAL VARS */
69
70 extern struct zebra_privs_t zserv_privs;
71
72 struct thread *t_irdp_raw;
73
74 /* Timer interval of irdp. */
75 int irdp_timer_interval = IRDP_DEFAULT_INTERVAL;
76
77 int
78 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_err ("irdp_sock_init: could not raise privs, %s",
86 safe_strerror (errno) );
87
88 sock = socket (AF_INET, SOCK_RAW, IPPROTO_ICMP);
89 save_errno = errno;
90
91 if ( zserv_privs.change (ZPRIVS_LOWER) )
92 zlog_err ("irdp_sock_init: could not lower privs, %s",
93 safe_strerror (errno) );
94
95 if (sock < 0) {
96 zlog_warn ("IRDP: can't create irdp socket %s", safe_strerror(save_errno));
97 return sock;
98 };
99
100 i = 1;
101 ret = setsockopt (sock, IPPROTO_IP, IP_TTL,
102 (void *) &i, sizeof (i));
103 if (ret < 0) {
104 zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
105 close(sock);
106 return ret;
107 };
108
109 ret = setsockopt_ifindex (AF_INET, sock, 1);
110 if (ret < 0) {
111 zlog_warn ("IRDP: can't do irdp sockopt %s", safe_strerror(errno));
112 close(sock);
113 return ret;
114 };
115
116 t_irdp_raw = NULL;
117 thread_add_read(zebrad.master, irdp_read_raw, NULL, sock, &t_irdp_raw);
118
119 return sock;
120 }
121
122
123 static int
124 get_pref(struct irdp_interface *irdp, struct prefix *p)
125 {
126 struct listnode *node;
127 struct Adv *adv;
128
129 /* Use default preference or use the override pref */
130
131 if( irdp->AdvPrefList == NULL )
132 return irdp->Preference;
133
134 for (ALL_LIST_ELEMENTS_RO (irdp->AdvPrefList, node, adv))
135 if( p->u.prefix4.s_addr == adv->ip.s_addr )
136 return adv->pref;
137
138 return irdp->Preference;
139 }
140
141 /* Make ICMP Router Advertisement Message. */
142 static int
143 make_advertisement_packet (struct interface *ifp,
144 struct prefix *p,
145 struct stream *s)
146 {
147 struct zebra_if *zi=ifp->info;
148 struct irdp_interface *irdp=&zi->irdp;
149 int size;
150 int pref;
151 u_int16_t checksum;
152
153 pref = get_pref(irdp, p);
154
155 stream_putc (s, ICMP_ROUTERADVERT); /* Type. */
156 stream_putc (s, 0); /* Code. */
157 stream_putw (s, 0); /* Checksum. */
158 stream_putc (s, 1); /* Num address. */
159 stream_putc (s, 2); /* Address Entry Size. */
160
161 if(irdp->flags & IF_SHUTDOWN)
162 stream_putw (s, 0);
163 else
164 stream_putw (s, irdp->Lifetime);
165
166 stream_putl (s, htonl(p->u.prefix4.s_addr)); /* Router address. */
167 stream_putl (s, pref);
168
169 /* in_cksum return network byte order value */
170 size = 16;
171 checksum = in_cksum (s->data, size);
172 stream_putw_at (s, 2, htons(checksum));
173
174 return size;
175 }
176
177 static void
178 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 u_int32_t dst;
184 u_int32_t ttl=1;
185
186 if (! (ifp->flags & IFF_UP)) return;
187
188 if (irdp->flags & IF_BROADCAST)
189 dst =INADDR_BROADCAST ;
190 else
191 dst = htonl(INADDR_ALLHOSTS_GROUP);
192
193 if(irdp->flags & IF_DEBUG_MESSAGES)
194 zlog_debug("IRDP: TX Advert on %s %s Holdtime=%d Preference=%d",
195 ifp->name,
196 prefix2str(p, buf, sizeof buf),
197 irdp->flags & IF_SHUTDOWN? 0 : irdp->Lifetime,
198 get_pref(irdp, p));
199
200 send_packet (ifp, s, dst, p, ttl);
201 }
202
203 static void irdp_advertisement (struct interface *ifp, struct prefix *p)
204 {
205 struct stream *s;
206 s = stream_new (128);
207 make_advertisement_packet (ifp, p, s);
208 irdp_send(ifp, p, s);
209 stream_free (s);
210 }
211
212 int irdp_send_thread(struct thread *t_advert)
213 {
214 u_int32_t timer, tmp;
215 struct interface *ifp = THREAD_ARG (t_advert);
216 struct zebra_if *zi=ifp->info;
217 struct irdp_interface *irdp=&zi->irdp;
218 struct prefix *p;
219 struct listnode *node, *nnode;
220 struct connected *ifc;
221
222 irdp->flags &= ~IF_SOLICIT;
223
224 if(ifp->connected)
225 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
226 {
227 p = ifc->address;
228
229 if (p->family != AF_INET)
230 continue;
231
232 irdp_advertisement(ifp, p);
233 irdp->irdp_sent++;
234 }
235
236 tmp = irdp->MaxAdvertInterval-irdp->MinAdvertInterval;
237 timer = random () % (tmp + 1);
238 timer = irdp->MinAdvertInterval + timer;
239
240 if(irdp->irdp_sent < MAX_INITIAL_ADVERTISEMENTS &&
241 timer > MAX_INITIAL_ADVERT_INTERVAL )
242 timer= MAX_INITIAL_ADVERT_INTERVAL;
243
244 if(irdp->flags & IF_DEBUG_MISC)
245 zlog_debug("IRDP: New timer for %s set to %u\n", ifp->name, timer);
246
247 irdp->t_advertise = NULL;
248 thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer,
249 &irdp->t_advertise);
250 return 0;
251 }
252
253 void irdp_advert_off(struct interface *ifp)
254 {
255 struct zebra_if *zi=ifp->info;
256 struct irdp_interface *irdp=&zi->irdp;
257 struct listnode *node, *nnode;
258 int i;
259 struct connected *ifc;
260 struct prefix *p;
261
262 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
263 irdp->t_advertise = NULL;
264
265 if(ifp->connected)
266 for (ALL_LIST_ELEMENTS (ifp->connected, node, nnode, ifc))
267 {
268 p = ifc->address;
269
270 /* Output some packets with Lifetime 0
271 we should add a wait...
272 */
273
274 for(i=0; i< IRDP_LAST_ADVERT_MESSAGES; i++)
275 {
276 irdp->irdp_sent++;
277 irdp_advertisement(ifp, p);
278 }
279 }
280 }
281
282
283 void process_solicit (struct interface *ifp)
284 {
285 struct zebra_if *zi=ifp->info;
286 struct irdp_interface *irdp=&zi->irdp;
287 u_int32_t timer;
288
289 /* When SOLICIT is active we reject further incoming solicits
290 this keeps down the answering rate so we don't have think
291 about DoS attacks here. */
292
293 if( irdp->flags & IF_SOLICIT) return;
294
295 irdp->flags |= IF_SOLICIT;
296 if(irdp->t_advertise) thread_cancel(irdp->t_advertise);
297 irdp->t_advertise = NULL;
298
299 timer = (random () % MAX_RESPONSE_DELAY) + 1;
300
301 irdp->t_advertise = NULL;
302 thread_add_timer(zebrad.master, irdp_send_thread, ifp, timer,
303 &irdp->t_advertise);
304 }
305
306 void irdp_finish()
307 {
308 struct vrf *vrf;
309 struct listnode *node, *nnode;
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_LIST_ELEMENTS (vrf->iflist, node, nnode, ifp))
318 {
319 zi = ifp->info;
320
321 if (!zi)
322 continue;
323 irdp = &zi->irdp;
324 if (!irdp)
325 continue;
326
327 if (irdp->flags & IF_ACTIVE )
328 {
329 irdp->flags |= IF_SHUTDOWN;
330 irdp_advert_off(ifp);
331 }
332 }
333 }
334
335 #endif /* HAVE_IRDP */