blob: 39f47805182181128390886ef3998efd84cbafa5 [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
63 listnode_delete (ifc->ifp->connected, ifc);
64 connected_free (ifc);
65}
66
67static void
68connected_announce (struct interface *ifp, struct connected *ifc)
69{
70 if (!ifc)
71 return;
72
73 listnode_add (ifp->connected, ifc);
74
75 /* Update interface address information to protocol daemon. */
76 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
77 {
78 if (ifc->address->family == AF_INET)
79 if_subnet_add (ifp, ifc);
80
81 SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
82
83 zebra_interface_address_add_update (ifp, ifc);
84
85 if (if_is_up(ifp))
86 {
87 if (ifc->address->family == AF_INET)
88 connected_up_ipv4 (ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000089#ifdef HAVE_IPV6
paulca162182005-09-12 16:58:52 +000090 else
91 connected_up_ipv6 (ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000092#endif
paulca162182005-09-12 16:58:52 +000093 }
94 }
95}
96
paul718e3742002-12-13 20:15:29 +000097/* If same interface address is already exist... */
98struct connected *
paulca162182005-09-12 16:58:52 +000099connected_check (struct interface *ifp, struct prefix *p)
paul718e3742002-12-13 20:15:29 +0000100{
101 struct connected *ifc;
hasso52dc7ee2004-09-23 19:18:23 +0000102 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000103
paul1eb8ef22005-04-07 07:30:20 +0000104 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
105 if (prefix_same (ifc->address, p))
106 return ifc;
paul718e3742002-12-13 20:15:29 +0000107
paul718e3742002-12-13 20:15:29 +0000108 return NULL;
109}
110
111/* Called from if_up(). */
112void
113connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
114{
115 struct prefix_ipv4 p;
116 struct prefix_ipv4 *addr;
117 struct prefix_ipv4 *dest;
118
119 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
120 return;
121
122 addr = (struct prefix_ipv4 *) ifc->address;
123 dest = (struct prefix_ipv4 *) ifc->destination;
124
125 memset (&p, 0, sizeof (struct prefix_ipv4));
126 p.family = AF_INET;
127 p.prefixlen = addr->prefixlen;
128
129 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000130 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000131 p.prefix = dest->prefix;
132 else
133 p.prefix = addr->prefix;
134
135 /* Apply mask to the network. */
136 apply_mask_ipv4 (&p);
137
138 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
139 address. */
140 if (prefix_ipv4_any (&p))
141 return;
142
paulc7133002006-01-17 17:56:18 +0000143 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0,
144 ifp->metric, 0);
paul718e3742002-12-13 20:15:29 +0000145
146 rib_update ();
147}
148
149/* Add connected IPv4 route to the interface. */
150void
151connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
pauld06b2a62005-10-11 03:53:54 +0000152 u_char prefixlen, struct in_addr *broad,
153 const char *label)
paul718e3742002-12-13 20:15:29 +0000154{
155 struct prefix_ipv4 *p;
156 struct connected *ifc;
157 struct connected *current;
158
159 /* Make connected structure. */
160 ifc = connected_new ();
161 ifc->ifp = ifp;
162 ifc->flags = flags;
163
164 /* Allocate new connected address. */
165 p = prefix_ipv4_new ();
166 p->family = AF_INET;
167 p->prefix = *addr;
168 p->prefixlen = prefixlen;
169 ifc->address = (struct prefix *) p;
paulca162182005-09-12 16:58:52 +0000170
paul718e3742002-12-13 20:15:29 +0000171 /* If there is broadcast or pointopoint address. */
172 if (broad)
173 {
174 p = prefix_ipv4_new ();
175 p->family = AF_INET;
176 p->prefix = *broad;
177 ifc->destination = (struct prefix *) p;
hasso3fb9cd62004-10-19 19:44:43 +0000178
179 /* validate the destination address */
180 if (ifp->flags & IFF_POINTOPOINT)
181 {
182 if (IPV4_ADDR_SAME(addr,broad))
183 zlog_warn("warning: PtP interface %s has same local and peer "
184 "address %s, routing protocols may malfunction",
185 ifp->name,inet_ntoa(*addr));
186 else if ((prefixlen != IPV4_MAX_PREFIXLEN) &&
187 (ipv4_network_addr(addr->s_addr,prefixlen) !=
188 ipv4_network_addr(broad->s_addr,prefixlen)))
189 {
190 char buf[2][INET_ADDRSTRLEN];
191 zlog_warn("warning: PtP interface %s network mismatch: local "
192 "%s/%d vs. peer %s, routing protocols may malfunction",
193 ifp->name,
194 inet_ntop (AF_INET, addr, buf[0], sizeof(buf[0])),
195 prefixlen,
196 inet_ntop (AF_INET, broad, buf[1], sizeof(buf[1])));
197 }
198 }
199 else
200 {
201 if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
202 {
203 char buf[2][INET_ADDRSTRLEN];
204 struct in_addr bcalc;
205 bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
206 zlog_warn("warning: interface %s broadcast addr %s/%d != "
207 "calculated %s, routing protocols may malfunction",
208 ifp->name,
209 inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
210 prefixlen,
211 inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
212 }
213 }
214
paul718e3742002-12-13 20:15:29 +0000215 }
hasso3fb9cd62004-10-19 19:44:43 +0000216 else
217 /* no broadcast or destination address was supplied */
ajs341a8f12004-12-22 16:32:16 +0000218 if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
219 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
220 "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
paul718e3742002-12-13 20:15:29 +0000221
222 /* Label of this address. */
223 if (label)
paul0752ef02005-11-03 12:35:21 +0000224 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
paul718e3742002-12-13 20:15:29 +0000225
226 /* Check same connected route. */
paulca162182005-09-12 16:58:52 +0000227 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
Andrew J. Schorr0f38dc42006-05-19 13:53:23 +0000228 {
229 if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
230 SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
231 connected_withdraw (current); /* implicit withdraw - freebsd does this */
232 }
paulca162182005-09-12 16:58:52 +0000233
234 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000235}
236
237void
238connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
239{
240 struct prefix_ipv4 p;
241 struct prefix_ipv4 *addr;
242 struct prefix_ipv4 *dest;
243
244 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
245 return;
246
247 addr = (struct prefix_ipv4 *)ifc->address;
248 dest = (struct prefix_ipv4 *)ifc->destination;
249
250 memset (&p, 0, sizeof (struct prefix_ipv4));
251 p.family = AF_INET;
252 p.prefixlen = addr->prefixlen;
253
paul960182a2003-04-09 07:16:04 +0000254 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000255 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000256 p.prefix = dest->prefix;
257 else
258 p.prefix = addr->prefix;
259
260 /* Apply mask to the network. */
261 apply_mask_ipv4 (&p);
262
263 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
264 address. */
265 if (prefix_ipv4_any (&p))
266 return;
267
268 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
269
270 rib_update ();
271}
272
273/* Delete connected IPv4 route to the interface. */
274void
275connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
paul0752ef02005-11-03 12:35:21 +0000276 u_char prefixlen, struct in_addr *broad)
paul718e3742002-12-13 20:15:29 +0000277{
278 struct prefix_ipv4 p;
279 struct connected *ifc;
280
281 memset (&p, 0, sizeof (struct prefix_ipv4));
282 p.family = AF_INET;
283 p.prefix = *addr;
284 p.prefixlen = prefixlen;
285
paulca162182005-09-12 16:58:52 +0000286 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000287 if (! ifc)
288 return;
paulca162182005-09-12 16:58:52 +0000289
290 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000291}
292
293#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +0000294void
295connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
296{
297 struct prefix_ipv6 p;
298 struct prefix_ipv6 *addr;
299 struct prefix_ipv6 *dest;
300
301 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
302 return;
303
304 addr = (struct prefix_ipv6 *) ifc->address;
305 dest = (struct prefix_ipv6 *) ifc->destination;
306
307 memset (&p, 0, sizeof (struct prefix_ipv6));
308 p.family = AF_INET6;
309 p.prefixlen = addr->prefixlen;
310
paul31a476c2003-09-29 19:54:53 +0000311 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000312 {
313 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
314 p.prefix = addr->prefix;
315 else
316 p.prefix = dest->prefix;
317 }
318 else
319 p.prefix = addr->prefix;
320
321 /* Apply mask to the network. */
322 apply_mask_ipv6 (&p);
323
hasso726f9b22003-05-25 21:04:54 +0000324#if ! defined (MUSICA) && ! defined (LINUX)
325 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
paul718e3742002-12-13 20:15:29 +0000326 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
327 return;
hasso726f9b22003-05-25 21:04:54 +0000328#endif
paul718e3742002-12-13 20:15:29 +0000329
paulc7133002006-01-17 17:56:18 +0000330 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0,
331 ifp->metric, 0);
paul718e3742002-12-13 20:15:29 +0000332
333 rib_update ();
334}
335
336/* Add connected IPv6 route to the interface. */
337void
338connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
paul89368d92005-11-26 09:14:07 +0000339 u_char prefixlen, struct in6_addr *broad,
340 const char *label)
paul718e3742002-12-13 20:15:29 +0000341{
342 struct prefix_ipv6 *p;
343 struct connected *ifc;
344 struct connected *current;
345
346 /* Make connected structure. */
347 ifc = connected_new ();
348 ifc->ifp = ifp;
349
350 /* Allocate new connected address. */
351 p = prefix_ipv6_new ();
352 p->family = AF_INET6;
353 IPV6_ADDR_COPY (&p->prefix, addr);
354 p->prefixlen = prefixlen;
355 ifc->address = (struct prefix *) p;
356
357 /* If there is broadcast or pointopoint address. */
358 if (broad)
359 {
360 p = prefix_ipv6_new ();
361 p->family = AF_INET6;
362 IPV6_ADDR_COPY (&p->prefix, broad);
363 ifc->destination = (struct prefix *) p;
364 }
365
paul0752ef02005-11-03 12:35:21 +0000366 /* Label of this address. */
367 if (label)
368 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
369
paulca162182005-09-12 16:58:52 +0000370 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
Andrew J. Schorr0f38dc42006-05-19 13:53:23 +0000371 {
372 if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
373 SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
374 connected_withdraw (current); /* implicit update of existing address */
375 }
paulca162182005-09-12 16:58:52 +0000376
377 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000378}
379
380void
381connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
382{
383 struct prefix_ipv6 p;
384 struct prefix_ipv6 *addr;
385 struct prefix_ipv6 *dest;
386
387 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
388 return;
389
390 addr = (struct prefix_ipv6 *) ifc->address;
391 dest = (struct prefix_ipv6 *) ifc->destination;
392
393 memset (&p, 0, sizeof (struct prefix_ipv6));
394 p.family = AF_INET6;
395 p.prefixlen = addr->prefixlen;
396
paul31a476c2003-09-29 19:54:53 +0000397 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000398 {
399 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
400 p.prefix = addr->prefix;
401 else
402 p.prefix = dest->prefix;
403 }
404 else
405 p.prefix = addr->prefix;
406
407 apply_mask_ipv6 (&p);
408
409 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
410 return;
411
412 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
413
414 rib_update ();
415}
416
417void
418connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
hassofce954f2004-10-07 20:29:24 +0000419 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000420{
421 struct prefix_ipv6 p;
422 struct connected *ifc;
423
424 memset (&p, 0, sizeof (struct prefix_ipv6));
425 p.family = AF_INET6;
426 memcpy (&p.prefix, address, sizeof (struct in6_addr));
427 p.prefixlen = prefixlen;
428
paulca162182005-09-12 16:58:52 +0000429 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000430 if (! ifc)
431 return;
432
paulca162182005-09-12 16:58:52 +0000433 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000434}
435#endif /* HAVE_IPV6 */