blob: 05538c5d49144284b730af94d4d7eff443cc26fc [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"
Denis Ovsienko6ce80bd2007-11-12 14:55:01 +000038extern struct zebra_t zebrad;
paul718e3742002-12-13 20:15:29 +000039
paulca162182005-09-12 16:58:52 +000040/* withdraw a connected address */
41static void
42connected_withdraw (struct connected *ifc)
43{
44 if (! ifc)
45 return;
46
47 /* Update interface address information to protocol daemon. */
48 if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
49 {
50 zebra_interface_address_delete_update (ifc->ifp, ifc);
51
52 if_subnet_delete (ifc->ifp, ifc);
53
54 if (ifc->address->family == AF_INET)
55 connected_down_ipv4 (ifc->ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000056#ifdef HAVE_IPV6
paulca162182005-09-12 16:58:52 +000057 else
58 connected_down_ipv6 (ifc->ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000059#endif
paulca162182005-09-12 16:58:52 +000060
61 UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
62 }
63
Andrew J. Schorr9c378512006-05-21 04:04:49 +000064 if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
65 {
66 listnode_delete (ifc->ifp->connected, ifc);
67 connected_free (ifc);
68 }
paulca162182005-09-12 16:58:52 +000069}
70
71static void
72connected_announce (struct interface *ifp, struct connected *ifc)
73{
74 if (!ifc)
75 return;
76
77 listnode_add (ifp->connected, ifc);
78
79 /* Update interface address information to protocol daemon. */
80 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
81 {
82 if (ifc->address->family == AF_INET)
83 if_subnet_add (ifp, ifc);
84
85 SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
86
87 zebra_interface_address_add_update (ifp, ifc);
88
Stephen Hemmingerfd213252008-07-05 16:32:37 -070089 if (if_is_operative(ifp))
paulca162182005-09-12 16:58:52 +000090 {
91 if (ifc->address->family == AF_INET)
92 connected_up_ipv4 (ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000093#ifdef HAVE_IPV6
paulca162182005-09-12 16:58:52 +000094 else
95 connected_up_ipv6 (ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000096#endif
paulca162182005-09-12 16:58:52 +000097 }
98 }
99}
100
paul718e3742002-12-13 20:15:29 +0000101/* If same interface address is already exist... */
102struct connected *
paulca162182005-09-12 16:58:52 +0000103connected_check (struct interface *ifp, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000104{
105 struct connected *ifc;
hasso52dc7ee2004-09-23 19:18:23 +0000106 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000107
paul1eb8ef22005-04-07 07:30:20 +0000108 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
109 if (prefix_same (ifc->address, p))
110 return ifc;
paul718e3742002-12-13 20:15:29 +0000111
paul718e3742002-12-13 20:15:29 +0000112 return NULL;
113}
114
Paul Jakma74ecdc92006-06-15 18:10:47 +0000115/* Check if two ifc's describe the same address */
116static int
117connected_same (struct connected *ifc1, struct connected *ifc2)
118{
119 if (ifc1->ifp != ifc2->ifp)
120 return 0;
121
122 if (ifc1->destination)
123 if (!ifc2->destination)
124 return 0;
125 if (ifc2->destination)
126 if (!ifc1->destination)
127 return 0;
128
129 if (ifc1->destination && ifc2->destination)
130 if (!prefix_same (ifc1->destination, ifc2->destination))
131 return 0;
132
133 if (ifc1->flags != ifc2->flags)
134 return 0;
135
136 return 1;
137}
138
139/* Handle implicit withdrawals of addresses, where a system ADDs an address
140 * to an interface which already has the same address configured.
141 *
142 * Returns the struct connected which must be announced to clients,
143 * or NULL if nothing to do.
144 */
145static struct connected *
146connected_implicit_withdraw (struct interface *ifp, struct connected *ifc)
147{
148 struct connected *current;
149
150 /* Check same connected route. */
151 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
152 {
153 if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
154 SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
155
156 /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
157 * back an address we have already added.
158 */
David Young33b931e2007-04-16 05:54:02 +0000159 if (connected_same (current, ifc) && CHECK_FLAG(current->conf, ZEBRA_IFC_REAL))
Paul Jakma74ecdc92006-06-15 18:10:47 +0000160 {
161 /* nothing to do */
162 connected_free (ifc);
163 return NULL;
164 }
165
166 UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
167 connected_withdraw (current); /* implicit withdraw - freebsd does this */
168 }
169 return ifc;
170}
171
paul718e3742002-12-13 20:15:29 +0000172/* Called from if_up(). */
173void
174connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
175{
176 struct prefix_ipv4 p;
paul718e3742002-12-13 20:15:29 +0000177
178 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
179 return;
180
Andrew J. Schorre4529632006-12-12 19:18:21 +0000181 PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
paul718e3742002-12-13 20:15:29 +0000182
183 /* Apply mask to the network. */
184 apply_mask_ipv4 (&p);
185
186 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
187 address. */
188 if (prefix_ipv4_any (&p))
189 return;
190
Paul Jakma7514fb72007-05-02 16:05:35 +0000191 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
G.Balajicddf3912011-11-26 21:59:32 +0400192 RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000193
G.Balaji42cb6b62012-04-02 23:31:29 +0530194 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
195 RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST);
196
paul718e3742002-12-13 20:15:29 +0000197 rib_update ();
198}
199
200/* Add connected IPv4 route to the interface. */
201void
202connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
pauld06b2a62005-10-11 03:53:54 +0000203 u_char prefixlen, struct in_addr *broad,
204 const char *label)
paul718e3742002-12-13 20:15:29 +0000205{
206 struct prefix_ipv4 *p;
207 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +0000208
209 /* Make connected structure. */
210 ifc = connected_new ();
211 ifc->ifp = ifp;
212 ifc->flags = flags;
213
214 /* Allocate new connected address. */
215 p = prefix_ipv4_new ();
216 p->family = AF_INET;
217 p->prefix = *addr;
218 p->prefixlen = prefixlen;
219 ifc->address = (struct prefix *) p;
paulca162182005-09-12 16:58:52 +0000220
Andrew J. Schorre4529632006-12-12 19:18:21 +0000221 /* If there is broadcast or peer address. */
paul718e3742002-12-13 20:15:29 +0000222 if (broad)
223 {
224 p = prefix_ipv4_new ();
225 p->family = AF_INET;
226 p->prefix = *broad;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000227 p->prefixlen = prefixlen;
paul718e3742002-12-13 20:15:29 +0000228 ifc->destination = (struct prefix *) p;
hasso3fb9cd62004-10-19 19:44:43 +0000229
230 /* validate the destination address */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000231 if (CONNECTED_PEER(ifc))
hasso3fb9cd62004-10-19 19:44:43 +0000232 {
233 if (IPV4_ADDR_SAME(addr,broad))
Andrew J. Schorre4529632006-12-12 19:18:21 +0000234 zlog_warn("warning: interface %s has same local and peer "
hasso3fb9cd62004-10-19 19:44:43 +0000235 "address %s, routing protocols may malfunction",
236 ifp->name,inet_ntoa(*addr));
hasso3fb9cd62004-10-19 19:44:43 +0000237 }
238 else
239 {
240 if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
241 {
242 char buf[2][INET_ADDRSTRLEN];
243 struct in_addr bcalc;
244 bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
245 zlog_warn("warning: interface %s broadcast addr %s/%d != "
246 "calculated %s, routing protocols may malfunction",
247 ifp->name,
248 inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
249 prefixlen,
250 inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
251 }
252 }
253
paul718e3742002-12-13 20:15:29 +0000254 }
hasso3fb9cd62004-10-19 19:44:43 +0000255 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000256 {
257 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER))
258 {
259 zlog_warn("warning: %s called for interface %s "
260 "with peer flag set, but no peer address supplied",
261 __func__, ifp->name);
262 UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
263 }
264
265 /* no broadcast or destination address was supplied */
266 if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
267 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
268 "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
269 }
paul718e3742002-12-13 20:15:29 +0000270
271 /* Label of this address. */
272 if (label)
paul0752ef02005-11-03 12:35:21 +0000273 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
paul718e3742002-12-13 20:15:29 +0000274
Paul Jakma74ecdc92006-06-15 18:10:47 +0000275 /* nothing to do? */
276 if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
277 return;
paulca162182005-09-12 16:58:52 +0000278
279 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000280}
281
282void
283connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
284{
285 struct prefix_ipv4 p;
paul718e3742002-12-13 20:15:29 +0000286
287 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
288 return;
289
Andrew J. Schorre4529632006-12-12 19:18:21 +0000290 PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
paul718e3742002-12-13 20:15:29 +0000291
292 /* Apply mask to the network. */
293 apply_mask_ipv4 (&p);
294
295 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
296 address. */
297 if (prefix_ipv4_any (&p))
298 return;
299
Denis Ovsienko6ce80bd2007-11-12 14:55:01 +0000300 /* Same logic as for connected_up_ipv4(): push the changes into the head. */
G.Balajicddf3912011-11-26 21:59:32 +0400301 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000302
G.Balaji42cb6b62012-04-02 23:31:29 +0530303 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_MULTICAST);
304
paul718e3742002-12-13 20:15:29 +0000305 rib_update ();
306}
307
308/* Delete connected IPv4 route to the interface. */
309void
310connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
paul0752ef02005-11-03 12:35:21 +0000311 u_char prefixlen, struct in_addr *broad)
paul718e3742002-12-13 20:15:29 +0000312{
313 struct prefix_ipv4 p;
314 struct connected *ifc;
315
316 memset (&p, 0, sizeof (struct prefix_ipv4));
317 p.family = AF_INET;
318 p.prefix = *addr;
319 p.prefixlen = prefixlen;
320
paulca162182005-09-12 16:58:52 +0000321 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000322 if (! ifc)
323 return;
paulca162182005-09-12 16:58:52 +0000324
325 connected_withdraw (ifc);
Stephen Hemminger90d2ab02009-04-29 21:54:59 -0700326
327 rib_update();
paul718e3742002-12-13 20:15:29 +0000328}
329
330#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +0000331void
332connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
333{
334 struct prefix_ipv6 p;
paul718e3742002-12-13 20:15:29 +0000335
336 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
337 return;
338
Andrew J. Schorre4529632006-12-12 19:18:21 +0000339 PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
paul718e3742002-12-13 20:15:29 +0000340
341 /* Apply mask to the network. */
342 apply_mask_ipv6 (&p);
343
hasso726f9b22003-05-25 21:04:54 +0000344#if ! defined (MUSICA) && ! defined (LINUX)
345 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
paul718e3742002-12-13 20:15:29 +0000346 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
347 return;
hasso726f9b22003-05-25 21:04:54 +0000348#endif
paul718e3742002-12-13 20:15:29 +0000349
Mathieu Goessensd13c3b42009-06-23 15:59:45 +0100350 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, RT_TABLE_MAIN,
G.Balajif768f362011-11-26 22:10:39 +0400351 ifp->metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000352
353 rib_update ();
354}
355
356/* Add connected IPv6 route to the interface. */
357void
Andrew J. Schorre4529632006-12-12 19:18:21 +0000358connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
paul89368d92005-11-26 09:14:07 +0000359 u_char prefixlen, struct in6_addr *broad,
360 const char *label)
paul718e3742002-12-13 20:15:29 +0000361{
362 struct prefix_ipv6 *p;
363 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +0000364
365 /* Make connected structure. */
366 ifc = connected_new ();
367 ifc->ifp = ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000368 ifc->flags = flags;
paul718e3742002-12-13 20:15:29 +0000369
370 /* Allocate new connected address. */
371 p = prefix_ipv6_new ();
372 p->family = AF_INET6;
373 IPV6_ADDR_COPY (&p->prefix, addr);
374 p->prefixlen = prefixlen;
375 ifc->address = (struct prefix *) p;
376
Andrew J. Schorre4529632006-12-12 19:18:21 +0000377 /* If there is broadcast or peer address. */
paul718e3742002-12-13 20:15:29 +0000378 if (broad)
379 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000380 if (IN6_IS_ADDR_UNSPECIFIED(broad))
381 zlog_warn("warning: %s called for interface %s with unspecified "
382 "destination address; ignoring!", __func__, ifp->name);
383 else
384 {
385 p = prefix_ipv6_new ();
386 p->family = AF_INET6;
387 IPV6_ADDR_COPY (&p->prefix, broad);
388 p->prefixlen = prefixlen;
389 ifc->destination = (struct prefix *) p;
390 }
391 }
392 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination)
393 {
394 zlog_warn("warning: %s called for interface %s "
395 "with peer flag set, but no peer address supplied",
396 __func__, ifp->name);
397 UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
paul718e3742002-12-13 20:15:29 +0000398 }
399
paul0752ef02005-11-03 12:35:21 +0000400 /* Label of this address. */
401 if (label)
402 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
403
Paul Jakma74ecdc92006-06-15 18:10:47 +0000404 if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
405 return;
paulca162182005-09-12 16:58:52 +0000406
407 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000408}
409
410void
411connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
412{
413 struct prefix_ipv6 p;
paul718e3742002-12-13 20:15:29 +0000414
415 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
416 return;
417
Andrew J. Schorre4529632006-12-12 19:18:21 +0000418 PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
paul718e3742002-12-13 20:15:29 +0000419
420 apply_mask_ipv6 (&p);
421
422 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
423 return;
424
G.Balajif768f362011-11-26 22:10:39 +0400425 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000426
427 rib_update ();
428}
429
430void
431connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
hassofce954f2004-10-07 20:29:24 +0000432 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000433{
434 struct prefix_ipv6 p;
435 struct connected *ifc;
436
437 memset (&p, 0, sizeof (struct prefix_ipv6));
438 p.family = AF_INET6;
439 memcpy (&p.prefix, address, sizeof (struct in6_addr));
440 p.prefixlen = prefixlen;
441
paulca162182005-09-12 16:58:52 +0000442 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000443 if (! ifc)
444 return;
445
paulca162182005-09-12 16:58:52 +0000446 connected_withdraw (ifc);
Stephen Hemminger90d2ab02009-04-29 21:54:59 -0700447
448 rib_update();
paul718e3742002-12-13 20:15:29 +0000449}
450#endif /* HAVE_IPV6 */