blob: 37aa456af8baedc2bf29abf1171dac2356042932 [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
114/* Called from if_up(). */
115void
116connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
117{
118 struct prefix_ipv4 p;
119 struct prefix_ipv4 *addr;
120 struct prefix_ipv4 *dest;
121
122 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
123 return;
124
125 addr = (struct prefix_ipv4 *) ifc->address;
126 dest = (struct prefix_ipv4 *) ifc->destination;
127
128 memset (&p, 0, sizeof (struct prefix_ipv4));
129 p.family = AF_INET;
130 p.prefixlen = addr->prefixlen;
131
132 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000133 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000134 p.prefix = dest->prefix;
135 else
136 p.prefix = addr->prefix;
137
138 /* Apply mask to the network. */
139 apply_mask_ipv4 (&p);
140
141 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
142 address. */
143 if (prefix_ipv4_any (&p))
144 return;
145
paulc7133002006-01-17 17:56:18 +0000146 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0,
147 ifp->metric, 0);
paul718e3742002-12-13 20:15:29 +0000148
149 rib_update ();
150}
151
152/* Add connected IPv4 route to the interface. */
153void
154connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
pauld06b2a62005-10-11 03:53:54 +0000155 u_char prefixlen, struct in_addr *broad,
156 const char *label)
paul718e3742002-12-13 20:15:29 +0000157{
158 struct prefix_ipv4 *p;
159 struct connected *ifc;
160 struct connected *current;
161
162 /* Make connected structure. */
163 ifc = connected_new ();
164 ifc->ifp = ifp;
165 ifc->flags = flags;
166
167 /* Allocate new connected address. */
168 p = prefix_ipv4_new ();
169 p->family = AF_INET;
170 p->prefix = *addr;
171 p->prefixlen = prefixlen;
172 ifc->address = (struct prefix *) p;
paulca162182005-09-12 16:58:52 +0000173
paul718e3742002-12-13 20:15:29 +0000174 /* If there is broadcast or pointopoint address. */
175 if (broad)
176 {
177 p = prefix_ipv4_new ();
178 p->family = AF_INET;
179 p->prefix = *broad;
180 ifc->destination = (struct prefix *) p;
hasso3fb9cd62004-10-19 19:44:43 +0000181
182 /* validate the destination address */
183 if (ifp->flags & IFF_POINTOPOINT)
184 {
185 if (IPV4_ADDR_SAME(addr,broad))
186 zlog_warn("warning: PtP interface %s has same local and peer "
187 "address %s, routing protocols may malfunction",
188 ifp->name,inet_ntoa(*addr));
189 else if ((prefixlen != IPV4_MAX_PREFIXLEN) &&
190 (ipv4_network_addr(addr->s_addr,prefixlen) !=
191 ipv4_network_addr(broad->s_addr,prefixlen)))
192 {
193 char buf[2][INET_ADDRSTRLEN];
194 zlog_warn("warning: PtP interface %s network mismatch: local "
195 "%s/%d vs. peer %s, routing protocols may malfunction",
196 ifp->name,
197 inet_ntop (AF_INET, addr, buf[0], sizeof(buf[0])),
198 prefixlen,
199 inet_ntop (AF_INET, broad, buf[1], sizeof(buf[1])));
200 }
201 }
202 else
203 {
204 if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
205 {
206 char buf[2][INET_ADDRSTRLEN];
207 struct in_addr bcalc;
208 bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
209 zlog_warn("warning: interface %s broadcast addr %s/%d != "
210 "calculated %s, routing protocols may malfunction",
211 ifp->name,
212 inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
213 prefixlen,
214 inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
215 }
216 }
217
paul718e3742002-12-13 20:15:29 +0000218 }
hasso3fb9cd62004-10-19 19:44:43 +0000219 else
220 /* no broadcast or destination address was supplied */
ajs341a8f12004-12-22 16:32:16 +0000221 if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
222 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
223 "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
paul718e3742002-12-13 20:15:29 +0000224
225 /* Label of this address. */
226 if (label)
paul0752ef02005-11-03 12:35:21 +0000227 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
paul718e3742002-12-13 20:15:29 +0000228
229 /* Check same connected route. */
paulca162182005-09-12 16:58:52 +0000230 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
Andrew J. Schorr0f38dc42006-05-19 13:53:23 +0000231 {
232 if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
Andrew J. Schorr9c378512006-05-21 04:04:49 +0000233 {
234 SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
235 UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
236 }
Andrew J. Schorr0f38dc42006-05-19 13:53:23 +0000237 connected_withdraw (current); /* implicit withdraw - freebsd does this */
238 }
paulca162182005-09-12 16:58:52 +0000239
240 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000241}
242
243void
244connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
245{
246 struct prefix_ipv4 p;
247 struct prefix_ipv4 *addr;
248 struct prefix_ipv4 *dest;
249
250 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
251 return;
252
253 addr = (struct prefix_ipv4 *)ifc->address;
254 dest = (struct prefix_ipv4 *)ifc->destination;
255
256 memset (&p, 0, sizeof (struct prefix_ipv4));
257 p.family = AF_INET;
258 p.prefixlen = addr->prefixlen;
259
paul960182a2003-04-09 07:16:04 +0000260 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000261 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000262 p.prefix = dest->prefix;
263 else
264 p.prefix = addr->prefix;
265
266 /* Apply mask to the network. */
267 apply_mask_ipv4 (&p);
268
269 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
270 address. */
271 if (prefix_ipv4_any (&p))
272 return;
273
274 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
275
276 rib_update ();
277}
278
279/* Delete connected IPv4 route to the interface. */
280void
281connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
paul0752ef02005-11-03 12:35:21 +0000282 u_char prefixlen, struct in_addr *broad)
paul718e3742002-12-13 20:15:29 +0000283{
284 struct prefix_ipv4 p;
285 struct connected *ifc;
286
287 memset (&p, 0, sizeof (struct prefix_ipv4));
288 p.family = AF_INET;
289 p.prefix = *addr;
290 p.prefixlen = prefixlen;
291
paulca162182005-09-12 16:58:52 +0000292 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000293 if (! ifc)
294 return;
paulca162182005-09-12 16:58:52 +0000295
296 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000297}
298
299#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +0000300void
301connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
302{
303 struct prefix_ipv6 p;
304 struct prefix_ipv6 *addr;
305 struct prefix_ipv6 *dest;
306
307 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
308 return;
309
310 addr = (struct prefix_ipv6 *) ifc->address;
311 dest = (struct prefix_ipv6 *) ifc->destination;
312
313 memset (&p, 0, sizeof (struct prefix_ipv6));
314 p.family = AF_INET6;
315 p.prefixlen = addr->prefixlen;
316
paul31a476c2003-09-29 19:54:53 +0000317 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000318 {
319 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
320 p.prefix = addr->prefix;
321 else
322 p.prefix = dest->prefix;
323 }
324 else
325 p.prefix = addr->prefix;
326
327 /* Apply mask to the network. */
328 apply_mask_ipv6 (&p);
329
hasso726f9b22003-05-25 21:04:54 +0000330#if ! defined (MUSICA) && ! defined (LINUX)
331 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
paul718e3742002-12-13 20:15:29 +0000332 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
333 return;
hasso726f9b22003-05-25 21:04:54 +0000334#endif
paul718e3742002-12-13 20:15:29 +0000335
paulc7133002006-01-17 17:56:18 +0000336 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0,
337 ifp->metric, 0);
paul718e3742002-12-13 20:15:29 +0000338
339 rib_update ();
340}
341
342/* Add connected IPv6 route to the interface. */
343void
344connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
paul89368d92005-11-26 09:14:07 +0000345 u_char prefixlen, struct in6_addr *broad,
346 const char *label)
paul718e3742002-12-13 20:15:29 +0000347{
348 struct prefix_ipv6 *p;
349 struct connected *ifc;
350 struct connected *current;
351
352 /* Make connected structure. */
353 ifc = connected_new ();
354 ifc->ifp = ifp;
355
356 /* Allocate new connected address. */
357 p = prefix_ipv6_new ();
358 p->family = AF_INET6;
359 IPV6_ADDR_COPY (&p->prefix, addr);
360 p->prefixlen = prefixlen;
361 ifc->address = (struct prefix *) p;
362
363 /* If there is broadcast or pointopoint address. */
364 if (broad)
365 {
366 p = prefix_ipv6_new ();
367 p->family = AF_INET6;
368 IPV6_ADDR_COPY (&p->prefix, broad);
369 ifc->destination = (struct prefix *) p;
370 }
371
paul0752ef02005-11-03 12:35:21 +0000372 /* Label of this address. */
373 if (label)
374 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
375
paulca162182005-09-12 16:58:52 +0000376 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
Andrew J. Schorr0f38dc42006-05-19 13:53:23 +0000377 {
378 if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
Andrew J. Schorr9c378512006-05-21 04:04:49 +0000379 {
380 SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
381 UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
382 }
Andrew J. Schorr0f38dc42006-05-19 13:53:23 +0000383 connected_withdraw (current); /* implicit update of existing address */
384 }
paulca162182005-09-12 16:58:52 +0000385
386 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000387}
388
389void
390connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
391{
392 struct prefix_ipv6 p;
393 struct prefix_ipv6 *addr;
394 struct prefix_ipv6 *dest;
395
396 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
397 return;
398
399 addr = (struct prefix_ipv6 *) ifc->address;
400 dest = (struct prefix_ipv6 *) ifc->destination;
401
402 memset (&p, 0, sizeof (struct prefix_ipv6));
403 p.family = AF_INET6;
404 p.prefixlen = addr->prefixlen;
405
paul31a476c2003-09-29 19:54:53 +0000406 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000407 {
408 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
409 p.prefix = addr->prefix;
410 else
411 p.prefix = dest->prefix;
412 }
413 else
414 p.prefix = addr->prefix;
415
416 apply_mask_ipv6 (&p);
417
418 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
419 return;
420
421 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
422
423 rib_update ();
424}
425
426void
427connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
hassofce954f2004-10-07 20:29:24 +0000428 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000429{
430 struct prefix_ipv6 p;
431 struct connected *ifc;
432
433 memset (&p, 0, sizeof (struct prefix_ipv6));
434 p.family = AF_INET6;
435 memcpy (&p.prefix, address, sizeof (struct in6_addr));
436 p.prefixlen = prefixlen;
437
paulca162182005-09-12 16:58:52 +0000438 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000439 if (! ifc)
440 return;
441
paulca162182005-09-12 16:58:52 +0000442 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000443}
444#endif /* HAVE_IPV6 */