blob: 38ab37d59e0c88724095212edad9af8d5a59ad04 [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
Christian Franke9db047f2013-01-24 14:04:44 +000052 if (ifc->address->family == AF_INET)
53 if_subnet_delete (ifc->ifp, ifc);
54
paulca162182005-09-12 16:58:52 +000055 if (ifc->address->family == AF_INET)
56 connected_down_ipv4 (ifc->ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000057#ifdef HAVE_IPV6
paulca162182005-09-12 16:58:52 +000058 else
59 connected_down_ipv6 (ifc->ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000060#endif
paulca162182005-09-12 16:58:52 +000061
62 UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
63 }
64
Andrew J. Schorr9c378512006-05-21 04:04:49 +000065 if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
66 {
67 listnode_delete (ifc->ifp->connected, ifc);
68 connected_free (ifc);
69 }
paulca162182005-09-12 16:58:52 +000070}
71
72static void
73connected_announce (struct interface *ifp, struct connected *ifc)
74{
75 if (!ifc)
76 return;
77
78 listnode_add (ifp->connected, ifc);
79
80 /* Update interface address information to protocol daemon. */
81 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
82 {
83 if (ifc->address->family == AF_INET)
84 if_subnet_add (ifp, ifc);
85
86 SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
87
88 zebra_interface_address_add_update (ifp, ifc);
89
Stephen Hemmingerfd213252008-07-05 16:32:37 -070090 if (if_is_operative(ifp))
paulca162182005-09-12 16:58:52 +000091 {
92 if (ifc->address->family == AF_INET)
93 connected_up_ipv4 (ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000094#ifdef HAVE_IPV6
paulca162182005-09-12 16:58:52 +000095 else
96 connected_up_ipv6 (ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000097#endif
paulca162182005-09-12 16:58:52 +000098 }
99 }
100}
101
paul718e3742002-12-13 20:15:29 +0000102/* If same interface address is already exist... */
103struct connected *
paulca162182005-09-12 16:58:52 +0000104connected_check (struct interface *ifp, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000105{
106 struct connected *ifc;
hasso52dc7ee2004-09-23 19:18:23 +0000107 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000108
paul1eb8ef22005-04-07 07:30:20 +0000109 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
110 if (prefix_same (ifc->address, p))
111 return ifc;
paul718e3742002-12-13 20:15:29 +0000112
paul718e3742002-12-13 20:15:29 +0000113 return NULL;
114}
115
Paul Jakma74ecdc92006-06-15 18:10:47 +0000116/* Check if two ifc's describe the same address */
117static int
118connected_same (struct connected *ifc1, struct connected *ifc2)
119{
120 if (ifc1->ifp != ifc2->ifp)
121 return 0;
122
123 if (ifc1->destination)
124 if (!ifc2->destination)
125 return 0;
126 if (ifc2->destination)
127 if (!ifc1->destination)
128 return 0;
129
130 if (ifc1->destination && ifc2->destination)
131 if (!prefix_same (ifc1->destination, ifc2->destination))
132 return 0;
133
134 if (ifc1->flags != ifc2->flags)
135 return 0;
136
137 return 1;
138}
139
Christian Franked7f5dad2013-01-24 14:04:46 +0000140/* Handle changes to addresses and send the neccesary announcements
141 * to clients. */
142static void
143connected_update(struct interface *ifp, struct connected *ifc)
Paul Jakma74ecdc92006-06-15 18:10:47 +0000144{
145 struct connected *current;
146
147 /* Check same connected route. */
148 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
149 {
150 if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
151 SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
152
153 /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
154 * back an address we have already added.
155 */
David Young33b931e2007-04-16 05:54:02 +0000156 if (connected_same (current, ifc) && CHECK_FLAG(current->conf, ZEBRA_IFC_REAL))
Paul Jakma74ecdc92006-06-15 18:10:47 +0000157 {
158 /* nothing to do */
159 connected_free (ifc);
Christian Franked7f5dad2013-01-24 14:04:46 +0000160 return;
Paul Jakma74ecdc92006-06-15 18:10:47 +0000161 }
Christian Franked7f5dad2013-01-24 14:04:46 +0000162
163 /* Clear the configured flag on the old ifc, so it will be freed by
164 * connected withdraw. */
Paul Jakma74ecdc92006-06-15 18:10:47 +0000165 UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
166 connected_withdraw (current); /* implicit withdraw - freebsd does this */
167 }
Christian Franked7f5dad2013-01-24 14:04:46 +0000168
169 /* If the connected is new or has changed, announce it */
170 connected_announce(ifp, ifc);
Paul Jakma74ecdc92006-06-15 18:10:47 +0000171}
172
paul718e3742002-12-13 20:15:29 +0000173/* Called from if_up(). */
174void
175connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
176{
177 struct prefix_ipv4 p;
paul718e3742002-12-13 20:15:29 +0000178
179 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
180 return;
181
Andrew J. Schorre4529632006-12-12 19:18:21 +0000182 PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
paul718e3742002-12-13 20:15:29 +0000183
184 /* Apply mask to the network. */
185 apply_mask_ipv4 (&p);
186
187 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
188 address. */
189 if (prefix_ipv4_any (&p))
190 return;
191
Paul Jakma7514fb72007-05-02 16:05:35 +0000192 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
G.Balajicddf3912011-11-26 21:59:32 +0400193 RT_TABLE_MAIN, ifp->metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000194
G.Balaji42cb6b62012-04-02 23:31:29 +0530195 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
196 RT_TABLE_MAIN, ifp->metric, 0, SAFI_MULTICAST);
197
paul718e3742002-12-13 20:15:29 +0000198 rib_update ();
199}
200
201/* Add connected IPv4 route to the interface. */
202void
203connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
pauld06b2a62005-10-11 03:53:54 +0000204 u_char prefixlen, struct in_addr *broad,
205 const char *label)
paul718e3742002-12-13 20:15:29 +0000206{
207 struct prefix_ipv4 *p;
208 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +0000209
210 /* Make connected structure. */
211 ifc = connected_new ();
212 ifc->ifp = ifp;
213 ifc->flags = flags;
214
215 /* Allocate new connected address. */
216 p = prefix_ipv4_new ();
217 p->family = AF_INET;
218 p->prefix = *addr;
219 p->prefixlen = prefixlen;
220 ifc->address = (struct prefix *) p;
paulca162182005-09-12 16:58:52 +0000221
Andrew J. Schorre4529632006-12-12 19:18:21 +0000222 /* If there is broadcast or peer address. */
paul718e3742002-12-13 20:15:29 +0000223 if (broad)
224 {
225 p = prefix_ipv4_new ();
226 p->family = AF_INET;
227 p->prefix = *broad;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000228 p->prefixlen = prefixlen;
paul718e3742002-12-13 20:15:29 +0000229 ifc->destination = (struct prefix *) p;
hasso3fb9cd62004-10-19 19:44:43 +0000230
231 /* validate the destination address */
Andrew J. Schorre4529632006-12-12 19:18:21 +0000232 if (CONNECTED_PEER(ifc))
hasso3fb9cd62004-10-19 19:44:43 +0000233 {
234 if (IPV4_ADDR_SAME(addr,broad))
Andrew J. Schorre4529632006-12-12 19:18:21 +0000235 zlog_warn("warning: interface %s has same local and peer "
hasso3fb9cd62004-10-19 19:44:43 +0000236 "address %s, routing protocols may malfunction",
237 ifp->name,inet_ntoa(*addr));
hasso3fb9cd62004-10-19 19:44:43 +0000238 }
239 else
240 {
241 if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
242 {
243 char buf[2][INET_ADDRSTRLEN];
244 struct in_addr bcalc;
245 bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
246 zlog_warn("warning: interface %s broadcast addr %s/%d != "
247 "calculated %s, routing protocols may malfunction",
248 ifp->name,
249 inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
250 prefixlen,
251 inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
252 }
253 }
254
paul718e3742002-12-13 20:15:29 +0000255 }
hasso3fb9cd62004-10-19 19:44:43 +0000256 else
Andrew J. Schorre4529632006-12-12 19:18:21 +0000257 {
258 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER))
259 {
260 zlog_warn("warning: %s called for interface %s "
261 "with peer flag set, but no peer address supplied",
262 __func__, ifp->name);
263 UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
264 }
265
266 /* no broadcast or destination address was supplied */
267 if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
268 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
269 "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
270 }
paul718e3742002-12-13 20:15:29 +0000271
272 /* Label of this address. */
273 if (label)
paul0752ef02005-11-03 12:35:21 +0000274 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
paul718e3742002-12-13 20:15:29 +0000275
Christian Franked7f5dad2013-01-24 14:04:46 +0000276 connected_update(ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000277}
278
279void
280connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
281{
282 struct prefix_ipv4 p;
paul718e3742002-12-13 20:15:29 +0000283
284 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
285 return;
286
Andrew J. Schorre4529632006-12-12 19:18:21 +0000287 PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
paul718e3742002-12-13 20:15:29 +0000288
289 /* Apply mask to the network. */
290 apply_mask_ipv4 (&p);
291
292 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
293 address. */
294 if (prefix_ipv4_any (&p))
295 return;
296
Denis Ovsienko6ce80bd2007-11-12 14:55:01 +0000297 /* Same logic as for connected_up_ipv4(): push the changes into the head. */
G.Balajicddf3912011-11-26 21:59:32 +0400298 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000299
G.Balaji42cb6b62012-04-02 23:31:29 +0530300 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_MULTICAST);
301
paul718e3742002-12-13 20:15:29 +0000302 rib_update ();
303}
304
305/* Delete connected IPv4 route to the interface. */
306void
307connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
paul0752ef02005-11-03 12:35:21 +0000308 u_char prefixlen, struct in_addr *broad)
paul718e3742002-12-13 20:15:29 +0000309{
310 struct prefix_ipv4 p;
311 struct connected *ifc;
312
313 memset (&p, 0, sizeof (struct prefix_ipv4));
314 p.family = AF_INET;
315 p.prefix = *addr;
316 p.prefixlen = prefixlen;
317
paulca162182005-09-12 16:58:52 +0000318 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000319 if (! ifc)
320 return;
paulca162182005-09-12 16:58:52 +0000321
322 connected_withdraw (ifc);
Stephen Hemminger90d2ab02009-04-29 21:54:59 -0700323
324 rib_update();
paul718e3742002-12-13 20:15:29 +0000325}
326
327#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +0000328void
329connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
330{
331 struct prefix_ipv6 p;
paul718e3742002-12-13 20:15:29 +0000332
333 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
334 return;
335
Andrew J. Schorre4529632006-12-12 19:18:21 +0000336 PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
paul718e3742002-12-13 20:15:29 +0000337
338 /* Apply mask to the network. */
339 apply_mask_ipv6 (&p);
340
hasso726f9b22003-05-25 21:04:54 +0000341#if ! defined (MUSICA) && ! defined (LINUX)
342 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
paul718e3742002-12-13 20:15:29 +0000343 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
344 return;
hasso726f9b22003-05-25 21:04:54 +0000345#endif
paul718e3742002-12-13 20:15:29 +0000346
Mathieu Goessensd13c3b42009-06-23 15:59:45 +0100347 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, RT_TABLE_MAIN,
G.Balajif768f362011-11-26 22:10:39 +0400348 ifp->metric, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000349
350 rib_update ();
351}
352
353/* Add connected IPv6 route to the interface. */
354void
Andrew J. Schorre4529632006-12-12 19:18:21 +0000355connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
paul89368d92005-11-26 09:14:07 +0000356 u_char prefixlen, struct in6_addr *broad,
357 const char *label)
paul718e3742002-12-13 20:15:29 +0000358{
359 struct prefix_ipv6 *p;
360 struct connected *ifc;
paul718e3742002-12-13 20:15:29 +0000361
362 /* Make connected structure. */
363 ifc = connected_new ();
364 ifc->ifp = ifp;
Andrew J. Schorre4529632006-12-12 19:18:21 +0000365 ifc->flags = flags;
paul718e3742002-12-13 20:15:29 +0000366
367 /* Allocate new connected address. */
368 p = prefix_ipv6_new ();
369 p->family = AF_INET6;
370 IPV6_ADDR_COPY (&p->prefix, addr);
371 p->prefixlen = prefixlen;
372 ifc->address = (struct prefix *) p;
373
Andrew J. Schorre4529632006-12-12 19:18:21 +0000374 /* If there is broadcast or peer address. */
paul718e3742002-12-13 20:15:29 +0000375 if (broad)
376 {
Andrew J. Schorre4529632006-12-12 19:18:21 +0000377 if (IN6_IS_ADDR_UNSPECIFIED(broad))
378 zlog_warn("warning: %s called for interface %s with unspecified "
379 "destination address; ignoring!", __func__, ifp->name);
380 else
381 {
382 p = prefix_ipv6_new ();
383 p->family = AF_INET6;
384 IPV6_ADDR_COPY (&p->prefix, broad);
385 p->prefixlen = prefixlen;
386 ifc->destination = (struct prefix *) p;
387 }
388 }
389 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination)
390 {
391 zlog_warn("warning: %s called for interface %s "
392 "with peer flag set, but no peer address supplied",
393 __func__, ifp->name);
394 UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
paul718e3742002-12-13 20:15:29 +0000395 }
396
paul0752ef02005-11-03 12:35:21 +0000397 /* Label of this address. */
398 if (label)
399 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
Christian Franked7f5dad2013-01-24 14:04:46 +0000400
401 connected_update(ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000402}
403
404void
405connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
406{
407 struct prefix_ipv6 p;
paul718e3742002-12-13 20:15:29 +0000408
409 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
410 return;
411
Andrew J. Schorre4529632006-12-12 19:18:21 +0000412 PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
paul718e3742002-12-13 20:15:29 +0000413
414 apply_mask_ipv6 (&p);
415
416 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
417 return;
418
G.Balajif768f362011-11-26 22:10:39 +0400419 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, SAFI_UNICAST);
paul718e3742002-12-13 20:15:29 +0000420
421 rib_update ();
422}
423
424void
425connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
hassofce954f2004-10-07 20:29:24 +0000426 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000427{
428 struct prefix_ipv6 p;
429 struct connected *ifc;
430
431 memset (&p, 0, sizeof (struct prefix_ipv6));
432 p.family = AF_INET6;
433 memcpy (&p.prefix, address, sizeof (struct in6_addr));
434 p.prefixlen = prefixlen;
435
paulca162182005-09-12 16:58:52 +0000436 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000437 if (! ifc)
438 return;
439
paulca162182005-09-12 16:58:52 +0000440 connected_withdraw (ifc);
Stephen Hemminger90d2ab02009-04-29 21:54:59 -0700441
442 rib_update();
paul718e3742002-12-13 20:15:29 +0000443}
444#endif /* HAVE_IPV6 */