blob: 44002e76d1b84b16baeef014a99efb814e0eb933 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
2 * Address linked list routine.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
4 *
5 * This file is part of GNU Zebra.
6 *
7 * GNU Zebra is free software; you can redistribute it and/or modify it
8 * under the terms of the GNU General Public License as published by the
9 * Free Software Foundation; either version 2, or (at your option) any
10 * later version.
11 *
12 * GNU Zebra is distributed in the hope that it will be useful, but
13 * WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 * General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with GNU Zebra; see the file COPYING. If not, write to the Free
19 * Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
20 * 02111-1307, USA.
21 */
22
23#include <zebra.h>
24
25#include "prefix.h"
26#include "linklist.h"
27#include "if.h"
28#include "table.h"
29#include "rib.h"
30#include "table.h"
31#include "log.h"
paul0752ef02005-11-03 12:35:21 +000032#include "memory.h"
paul718e3742002-12-13 20:15:29 +000033
34#include "zebra/zserv.h"
35#include "zebra/redistribute.h"
hassoeef1fe12004-10-03 18:46:08 +000036#include "zebra/interface.h"
paula1ac18c2005-06-28 17:17:12 +000037#include "zebra/connected.h"
paul718e3742002-12-13 20:15:29 +000038
paulca162182005-09-12 16:58:52 +000039/* withdraw a connected address */
40static void
41connected_withdraw (struct connected *ifc)
42{
43 if (! ifc)
44 return;
45
46 /* Update interface address information to protocol daemon. */
47 if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
48 {
49 zebra_interface_address_delete_update (ifc->ifp, ifc);
50
51 if_subnet_delete (ifc->ifp, ifc);
52
53 if (ifc->address->family == AF_INET)
54 connected_down_ipv4 (ifc->ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000055#ifdef HAVE_IPV6
paulca162182005-09-12 16:58:52 +000056 else
57 connected_down_ipv6 (ifc->ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000058#endif
paulca162182005-09-12 16:58:52 +000059
60 UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
61 }
62
Andrew J. Schorr9c378512006-05-21 04:04:49 +000063 if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
64 {
65 listnode_delete (ifc->ifp->connected, ifc);
66 connected_free (ifc);
67 }
paulca162182005-09-12 16:58:52 +000068}
69
70static void
71connected_announce (struct interface *ifp, struct connected *ifc)
72{
73 if (!ifc)
74 return;
75
76 listnode_add (ifp->connected, ifc);
77
78 /* Update interface address information to protocol daemon. */
79 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
80 {
81 if (ifc->address->family == AF_INET)
82 if_subnet_add (ifp, ifc);
83
84 SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
85
86 zebra_interface_address_add_update (ifp, ifc);
87
88 if (if_is_up(ifp))
89 {
90 if (ifc->address->family == AF_INET)
91 connected_up_ipv4 (ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000092#ifdef HAVE_IPV6
paulca162182005-09-12 16:58:52 +000093 else
94 connected_up_ipv6 (ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000095#endif
paulca162182005-09-12 16:58:52 +000096 }
97 }
98}
99
paul718e3742002-12-13 20:15:29 +0000100/* If same interface address is already exist... */
101struct connected *
paulca162182005-09-12 16:58:52 +0000102connected_check (struct interface *ifp, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000103{
104 struct connected *ifc;
hasso52dc7ee2004-09-23 19:18:23 +0000105 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000106
paul1eb8ef22005-04-07 07:30:20 +0000107 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
108 if (prefix_same (ifc->address, p))
109 return ifc;
paul718e3742002-12-13 20:15:29 +0000110
paul718e3742002-12-13 20:15:29 +0000111 return NULL;
112}
113
Paul Jakma74ecdc92006-06-15 18:10:47 +0000114/* Check if two ifc's describe the same address */
115static int
116connected_same (struct connected *ifc1, struct connected *ifc2)
117{
118 if (ifc1->ifp != ifc2->ifp)
119 return 0;
120
121 if (ifc1->destination)
122 if (!ifc2->destination)
123 return 0;
124 if (ifc2->destination)
125 if (!ifc1->destination)
126 return 0;
127
128 if (ifc1->destination && ifc2->destination)
129 if (!prefix_same (ifc1->destination, ifc2->destination))
130 return 0;
131
132 if (ifc1->flags != ifc2->flags)
133 return 0;
134
135 return 1;
136}
137
138/* Handle implicit withdrawals of addresses, where a system ADDs an address
139 * to an interface which already has the same address configured.
140 *
141 * Returns the struct connected which must be announced to clients,
142 * or NULL if nothing to do.
143 */
144static struct connected *
145connected_implicit_withdraw (struct interface *ifp, struct connected *ifc)
146{
147 struct connected *current;
148
149 /* Check same connected route. */
150 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
151 {
152 if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
153 SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
154
155 /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
156 * back an address we have already added.
157 */
158 if (connected_same (current, ifc))
159 {
160 /* nothing to do */
161 connected_free (ifc);
162 return NULL;
163 }
164
165 UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
166 connected_withdraw (current); /* implicit withdraw - freebsd does this */
167 }
168 return ifc;
169}
170
paul718e3742002-12-13 20:15:29 +0000171/* Called from if_up(). */
172void
173connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
174{
175 struct prefix_ipv4 p;
176 struct prefix_ipv4 *addr;
177 struct prefix_ipv4 *dest;
178
179 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
180 return;
181
182 addr = (struct prefix_ipv4 *) ifc->address;
183 dest = (struct prefix_ipv4 *) ifc->destination;
184
185 memset (&p, 0, sizeof (struct prefix_ipv4));
186 p.family = AF_INET;
187 p.prefixlen = addr->prefixlen;
188
189 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000190 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000191 p.prefix = dest->prefix;
192 else
193 p.prefix = addr->prefix;
194
195 /* Apply mask to the network. */
196 apply_mask_ipv4 (&p);
197
198 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
199 address. */
200 if (prefix_ipv4_any (&p))
201 return;
202
Paul Jakma171eee32006-07-27 16:11:02 +0000203 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, RT_TABLE_MAIN,
paulc7133002006-01-17 17:56:18 +0000204 ifp->metric, 0);
paul718e3742002-12-13 20:15:29 +0000205
206 rib_update ();
207}
208
209/* Add connected IPv4 route to the interface. */
210void
211connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
pauld06b2a62005-10-11 03:53:54 +0000212 u_char prefixlen, struct in_addr *broad,
213 const char *label)
paul718e3742002-12-13 20:15:29 +0000214{
215 struct prefix_ipv4 *p;
216 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +0000217
218 /* Make connected structure. */
219 ifc = connected_new ();
220 ifc->ifp = ifp;
221 ifc->flags = flags;
222
223 /* Allocate new connected address. */
224 p = prefix_ipv4_new ();
225 p->family = AF_INET;
226 p->prefix = *addr;
227 p->prefixlen = prefixlen;
228 ifc->address = (struct prefix *) p;
paulca162182005-09-12 16:58:52 +0000229
paul718e3742002-12-13 20:15:29 +0000230 /* If there is broadcast or pointopoint address. */
231 if (broad)
232 {
233 p = prefix_ipv4_new ();
234 p->family = AF_INET;
235 p->prefix = *broad;
236 ifc->destination = (struct prefix *) p;
hasso3fb9cd62004-10-19 19:44:43 +0000237
238 /* validate the destination address */
239 if (ifp->flags & IFF_POINTOPOINT)
240 {
241 if (IPV4_ADDR_SAME(addr,broad))
242 zlog_warn("warning: PtP interface %s has same local and peer "
243 "address %s, routing protocols may malfunction",
244 ifp->name,inet_ntoa(*addr));
245 else if ((prefixlen != IPV4_MAX_PREFIXLEN) &&
246 (ipv4_network_addr(addr->s_addr,prefixlen) !=
247 ipv4_network_addr(broad->s_addr,prefixlen)))
248 {
249 char buf[2][INET_ADDRSTRLEN];
250 zlog_warn("warning: PtP interface %s network mismatch: local "
251 "%s/%d vs. peer %s, routing protocols may malfunction",
252 ifp->name,
253 inet_ntop (AF_INET, addr, buf[0], sizeof(buf[0])),
254 prefixlen,
255 inet_ntop (AF_INET, broad, buf[1], sizeof(buf[1])));
256 }
257 }
258 else
259 {
260 if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
261 {
262 char buf[2][INET_ADDRSTRLEN];
263 struct in_addr bcalc;
264 bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
265 zlog_warn("warning: interface %s broadcast addr %s/%d != "
266 "calculated %s, routing protocols may malfunction",
267 ifp->name,
268 inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
269 prefixlen,
270 inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
271 }
272 }
273
paul718e3742002-12-13 20:15:29 +0000274 }
hasso3fb9cd62004-10-19 19:44:43 +0000275 else
276 /* no broadcast or destination address was supplied */
ajs341a8f12004-12-22 16:32:16 +0000277 if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
278 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
279 "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
paul718e3742002-12-13 20:15:29 +0000280
281 /* Label of this address. */
282 if (label)
paul0752ef02005-11-03 12:35:21 +0000283 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
paul718e3742002-12-13 20:15:29 +0000284
Paul Jakma74ecdc92006-06-15 18:10:47 +0000285 /* nothing to do? */
286 if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
287 return;
paulca162182005-09-12 16:58:52 +0000288
289 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000290}
291
292void
293connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
294{
295 struct prefix_ipv4 p;
296 struct prefix_ipv4 *addr;
297 struct prefix_ipv4 *dest;
298
299 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
300 return;
301
302 addr = (struct prefix_ipv4 *)ifc->address;
303 dest = (struct prefix_ipv4 *)ifc->destination;
304
305 memset (&p, 0, sizeof (struct prefix_ipv4));
306 p.family = AF_INET;
307 p.prefixlen = addr->prefixlen;
308
paul960182a2003-04-09 07:16:04 +0000309 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000310 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000311 p.prefix = dest->prefix;
312 else
313 p.prefix = addr->prefix;
314
315 /* Apply mask to the network. */
316 apply_mask_ipv4 (&p);
317
318 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
319 address. */
320 if (prefix_ipv4_any (&p))
321 return;
322
323 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
324
325 rib_update ();
326}
327
328/* Delete connected IPv4 route to the interface. */
329void
330connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
paul0752ef02005-11-03 12:35:21 +0000331 u_char prefixlen, struct in_addr *broad)
paul718e3742002-12-13 20:15:29 +0000332{
333 struct prefix_ipv4 p;
334 struct connected *ifc;
335
336 memset (&p, 0, sizeof (struct prefix_ipv4));
337 p.family = AF_INET;
338 p.prefix = *addr;
339 p.prefixlen = prefixlen;
340
paulca162182005-09-12 16:58:52 +0000341 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000342 if (! ifc)
343 return;
paulca162182005-09-12 16:58:52 +0000344
345 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000346}
347
348#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +0000349void
350connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
351{
352 struct prefix_ipv6 p;
353 struct prefix_ipv6 *addr;
354 struct prefix_ipv6 *dest;
355
356 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
357 return;
358
359 addr = (struct prefix_ipv6 *) ifc->address;
360 dest = (struct prefix_ipv6 *) ifc->destination;
361
362 memset (&p, 0, sizeof (struct prefix_ipv6));
363 p.family = AF_INET6;
364 p.prefixlen = addr->prefixlen;
365
paul31a476c2003-09-29 19:54:53 +0000366 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000367 {
368 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
369 p.prefix = addr->prefix;
370 else
371 p.prefix = dest->prefix;
372 }
373 else
374 p.prefix = addr->prefix;
375
376 /* Apply mask to the network. */
377 apply_mask_ipv6 (&p);
378
hasso726f9b22003-05-25 21:04:54 +0000379#if ! defined (MUSICA) && ! defined (LINUX)
380 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
paul718e3742002-12-13 20:15:29 +0000381 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
382 return;
hasso726f9b22003-05-25 21:04:54 +0000383#endif
paul718e3742002-12-13 20:15:29 +0000384
paulc7133002006-01-17 17:56:18 +0000385 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0,
386 ifp->metric, 0);
paul718e3742002-12-13 20:15:29 +0000387
388 rib_update ();
389}
390
391/* Add connected IPv6 route to the interface. */
392void
393connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
paul89368d92005-11-26 09:14:07 +0000394 u_char prefixlen, struct in6_addr *broad,
395 const char *label)
paul718e3742002-12-13 20:15:29 +0000396{
397 struct prefix_ipv6 *p;
398 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +0000399
400 /* Make connected structure. */
401 ifc = connected_new ();
402 ifc->ifp = ifp;
403
404 /* Allocate new connected address. */
405 p = prefix_ipv6_new ();
406 p->family = AF_INET6;
407 IPV6_ADDR_COPY (&p->prefix, addr);
408 p->prefixlen = prefixlen;
409 ifc->address = (struct prefix *) p;
410
411 /* If there is broadcast or pointopoint address. */
412 if (broad)
413 {
414 p = prefix_ipv6_new ();
415 p->family = AF_INET6;
416 IPV6_ADDR_COPY (&p->prefix, broad);
417 ifc->destination = (struct prefix *) p;
418 }
419
paul0752ef02005-11-03 12:35:21 +0000420 /* Label of this address. */
421 if (label)
422 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
423
Paul Jakma74ecdc92006-06-15 18:10:47 +0000424 if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
425 return;
paulca162182005-09-12 16:58:52 +0000426
427 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000428}
429
430void
431connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
432{
433 struct prefix_ipv6 p;
434 struct prefix_ipv6 *addr;
435 struct prefix_ipv6 *dest;
436
437 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
438 return;
439
440 addr = (struct prefix_ipv6 *) ifc->address;
441 dest = (struct prefix_ipv6 *) ifc->destination;
442
443 memset (&p, 0, sizeof (struct prefix_ipv6));
444 p.family = AF_INET6;
445 p.prefixlen = addr->prefixlen;
446
paul31a476c2003-09-29 19:54:53 +0000447 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000448 {
449 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
450 p.prefix = addr->prefix;
451 else
452 p.prefix = dest->prefix;
453 }
454 else
455 p.prefix = addr->prefix;
456
457 apply_mask_ipv6 (&p);
458
459 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
460 return;
461
462 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
463
464 rib_update ();
465}
466
467void
468connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
hassofce954f2004-10-07 20:29:24 +0000469 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000470{
471 struct prefix_ipv6 p;
472 struct connected *ifc;
473
474 memset (&p, 0, sizeof (struct prefix_ipv6));
475 p.family = AF_INET6;
476 memcpy (&p.prefix, address, sizeof (struct in6_addr));
477 p.prefixlen = prefixlen;
478
paulca162182005-09-12 16:58:52 +0000479 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000480 if (! ifc)
481 return;
482
paulca162182005-09-12 16:58:52 +0000483 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000484}
485#endif /* HAVE_IPV6 */