blob: 58d964fc5b74977917ec7dc52d53e45b1dda5f2e [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"
32
33#include "zebra/zserv.h"
34#include "zebra/redistribute.h"
hassoeef1fe12004-10-03 18:46:08 +000035#include "zebra/interface.h"
paula1ac18c2005-06-28 17:17:12 +000036#include "zebra/connected.h"
paul718e3742002-12-13 20:15:29 +000037
paulca162182005-09-12 16:58:52 +000038/* withdraw a connected address */
39static void
40connected_withdraw (struct connected *ifc)
41{
42 if (! ifc)
43 return;
44
45 /* Update interface address information to protocol daemon. */
46 if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
47 {
48 zebra_interface_address_delete_update (ifc->ifp, ifc);
49
50 if_subnet_delete (ifc->ifp, ifc);
51
52 if (ifc->address->family == AF_INET)
53 connected_down_ipv4 (ifc->ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000054#ifdef HAVE_IPV6
paulca162182005-09-12 16:58:52 +000055 else
56 connected_down_ipv6 (ifc->ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000057#endif
paulca162182005-09-12 16:58:52 +000058
59 UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
60 }
61
62 listnode_delete (ifc->ifp->connected, ifc);
63 connected_free (ifc);
64}
65
66static void
67connected_announce (struct interface *ifp, struct connected *ifc)
68{
69 if (!ifc)
70 return;
71
72 listnode_add (ifp->connected, ifc);
73
74 /* Update interface address information to protocol daemon. */
75 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
76 {
77 if (ifc->address->family == AF_INET)
78 if_subnet_add (ifp, ifc);
79
80 SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
81
82 zebra_interface_address_add_update (ifp, ifc);
83
84 if (if_is_up(ifp))
85 {
86 if (ifc->address->family == AF_INET)
87 connected_up_ipv4 (ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000088#ifdef HAVE_IPV6
paulca162182005-09-12 16:58:52 +000089 else
90 connected_up_ipv6 (ifp, ifc);
vincentaa2e32b2005-09-28 13:42:11 +000091#endif
paulca162182005-09-12 16:58:52 +000092 }
93 }
94}
95
paul718e3742002-12-13 20:15:29 +000096/* If same interface address is already exist... */
97struct connected *
paulca162182005-09-12 16:58:52 +000098connected_check (struct interface *ifp, struct prefix *p)
paul718e3742002-12-13 20:15:29 +000099{
100 struct connected *ifc;
hasso52dc7ee2004-09-23 19:18:23 +0000101 struct listnode *node;
paul718e3742002-12-13 20:15:29 +0000102
paul1eb8ef22005-04-07 07:30:20 +0000103 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
104 if (prefix_same (ifc->address, p))
105 return ifc;
paul718e3742002-12-13 20:15:29 +0000106
paul718e3742002-12-13 20:15:29 +0000107 return NULL;
108}
109
110/* Called from if_up(). */
111void
112connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
113{
114 struct prefix_ipv4 p;
115 struct prefix_ipv4 *addr;
116 struct prefix_ipv4 *dest;
117
118 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
119 return;
120
121 addr = (struct prefix_ipv4 *) ifc->address;
122 dest = (struct prefix_ipv4 *) ifc->destination;
123
124 memset (&p, 0, sizeof (struct prefix_ipv4));
125 p.family = AF_INET;
126 p.prefixlen = addr->prefixlen;
127
128 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000129 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000130 p.prefix = dest->prefix;
131 else
132 p.prefix = addr->prefix;
133
134 /* Apply mask to the network. */
135 apply_mask_ipv4 (&p);
136
137 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
138 address. */
139 if (prefix_ipv4_any (&p))
140 return;
141
142 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0);
143
144 rib_update ();
145}
146
147/* Add connected IPv4 route to the interface. */
148void
149connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
pauld06b2a62005-10-11 03:53:54 +0000150 u_char prefixlen, struct in_addr *broad,
151 const char *label)
paul718e3742002-12-13 20:15:29 +0000152{
153 struct prefix_ipv4 *p;
154 struct connected *ifc;
155 struct connected *current;
156
157 /* Make connected structure. */
158 ifc = connected_new ();
159 ifc->ifp = ifp;
160 ifc->flags = flags;
161
162 /* Allocate new connected address. */
163 p = prefix_ipv4_new ();
164 p->family = AF_INET;
165 p->prefix = *addr;
166 p->prefixlen = prefixlen;
167 ifc->address = (struct prefix *) p;
paulca162182005-09-12 16:58:52 +0000168
paul718e3742002-12-13 20:15:29 +0000169 /* If there is broadcast or pointopoint address. */
170 if (broad)
171 {
172 p = prefix_ipv4_new ();
173 p->family = AF_INET;
174 p->prefix = *broad;
175 ifc->destination = (struct prefix *) p;
hasso3fb9cd62004-10-19 19:44:43 +0000176
177 /* validate the destination address */
178 if (ifp->flags & IFF_POINTOPOINT)
179 {
180 if (IPV4_ADDR_SAME(addr,broad))
181 zlog_warn("warning: PtP interface %s has same local and peer "
182 "address %s, routing protocols may malfunction",
183 ifp->name,inet_ntoa(*addr));
184 else if ((prefixlen != IPV4_MAX_PREFIXLEN) &&
185 (ipv4_network_addr(addr->s_addr,prefixlen) !=
186 ipv4_network_addr(broad->s_addr,prefixlen)))
187 {
188 char buf[2][INET_ADDRSTRLEN];
189 zlog_warn("warning: PtP interface %s network mismatch: local "
190 "%s/%d vs. peer %s, routing protocols may malfunction",
191 ifp->name,
192 inet_ntop (AF_INET, addr, buf[0], sizeof(buf[0])),
193 prefixlen,
194 inet_ntop (AF_INET, broad, buf[1], sizeof(buf[1])));
195 }
196 }
197 else
198 {
199 if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
200 {
201 char buf[2][INET_ADDRSTRLEN];
202 struct in_addr bcalc;
203 bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
204 zlog_warn("warning: interface %s broadcast addr %s/%d != "
205 "calculated %s, routing protocols may malfunction",
206 ifp->name,
207 inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
208 prefixlen,
209 inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
210 }
211 }
212
paul718e3742002-12-13 20:15:29 +0000213 }
hasso3fb9cd62004-10-19 19:44:43 +0000214 else
215 /* no broadcast or destination address was supplied */
ajs341a8f12004-12-22 16:32:16 +0000216 if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
217 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
218 "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
paul718e3742002-12-13 20:15:29 +0000219
220 /* Label of this address. */
221 if (label)
222 ifc->label = strdup (label);
223
224 /* Check same connected route. */
paulca162182005-09-12 16:58:52 +0000225 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
226 connected_withdraw (current); /* implicit withdraw - freebsd does this */
227
228 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000229}
230
231void
232connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
233{
234 struct prefix_ipv4 p;
235 struct prefix_ipv4 *addr;
236 struct prefix_ipv4 *dest;
237
238 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
239 return;
240
241 addr = (struct prefix_ipv4 *)ifc->address;
242 dest = (struct prefix_ipv4 *)ifc->destination;
243
244 memset (&p, 0, sizeof (struct prefix_ipv4));
245 p.family = AF_INET;
246 p.prefixlen = addr->prefixlen;
247
paul960182a2003-04-09 07:16:04 +0000248 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000249 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000250 p.prefix = dest->prefix;
251 else
252 p.prefix = addr->prefix;
253
254 /* Apply mask to the network. */
255 apply_mask_ipv4 (&p);
256
257 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
258 address. */
259 if (prefix_ipv4_any (&p))
260 return;
261
262 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
263
264 rib_update ();
265}
266
267/* Delete connected IPv4 route to the interface. */
268void
269connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
pauld06b2a62005-10-11 03:53:54 +0000270 u_char prefixlen, struct in_addr *broad,
271 const char *label)
paul718e3742002-12-13 20:15:29 +0000272{
273 struct prefix_ipv4 p;
274 struct connected *ifc;
275
276 memset (&p, 0, sizeof (struct prefix_ipv4));
277 p.family = AF_INET;
278 p.prefix = *addr;
279 p.prefixlen = prefixlen;
280
paulca162182005-09-12 16:58:52 +0000281 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000282 if (! ifc)
283 return;
paulca162182005-09-12 16:58:52 +0000284
285 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000286}
287
288#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +0000289void
290connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
291{
292 struct prefix_ipv6 p;
293 struct prefix_ipv6 *addr;
294 struct prefix_ipv6 *dest;
295
296 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
297 return;
298
299 addr = (struct prefix_ipv6 *) ifc->address;
300 dest = (struct prefix_ipv6 *) ifc->destination;
301
302 memset (&p, 0, sizeof (struct prefix_ipv6));
303 p.family = AF_INET6;
304 p.prefixlen = addr->prefixlen;
305
paul31a476c2003-09-29 19:54:53 +0000306 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000307 {
308 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
309 p.prefix = addr->prefix;
310 else
311 p.prefix = dest->prefix;
312 }
313 else
314 p.prefix = addr->prefix;
315
316 /* Apply mask to the network. */
317 apply_mask_ipv6 (&p);
318
hasso726f9b22003-05-25 21:04:54 +0000319#if ! defined (MUSICA) && ! defined (LINUX)
320 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
paul718e3742002-12-13 20:15:29 +0000321 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
322 return;
hasso726f9b22003-05-25 21:04:54 +0000323#endif
paul718e3742002-12-13 20:15:29 +0000324
hassobe61c4e2005-08-27 06:05:47 +0000325 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +0000326
327 rib_update ();
328}
329
330/* Add connected IPv6 route to the interface. */
331void
332connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
hassofce954f2004-10-07 20:29:24 +0000333 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000334{
335 struct prefix_ipv6 *p;
336 struct connected *ifc;
337 struct connected *current;
338
339 /* Make connected structure. */
340 ifc = connected_new ();
341 ifc->ifp = ifp;
342
343 /* Allocate new connected address. */
344 p = prefix_ipv6_new ();
345 p->family = AF_INET6;
346 IPV6_ADDR_COPY (&p->prefix, addr);
347 p->prefixlen = prefixlen;
348 ifc->address = (struct prefix *) p;
349
350 /* If there is broadcast or pointopoint address. */
351 if (broad)
352 {
353 p = prefix_ipv6_new ();
354 p->family = AF_INET6;
355 IPV6_ADDR_COPY (&p->prefix, broad);
356 ifc->destination = (struct prefix *) p;
357 }
358
paulca162182005-09-12 16:58:52 +0000359 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
360 connected_withdraw (current); /* implicit update of existing address */
361
362 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000363}
364
365void
366connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
367{
368 struct prefix_ipv6 p;
369 struct prefix_ipv6 *addr;
370 struct prefix_ipv6 *dest;
371
372 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
373 return;
374
375 addr = (struct prefix_ipv6 *) ifc->address;
376 dest = (struct prefix_ipv6 *) ifc->destination;
377
378 memset (&p, 0, sizeof (struct prefix_ipv6));
379 p.family = AF_INET6;
380 p.prefixlen = addr->prefixlen;
381
paul31a476c2003-09-29 19:54:53 +0000382 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000383 {
384 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
385 p.prefix = addr->prefix;
386 else
387 p.prefix = dest->prefix;
388 }
389 else
390 p.prefix = addr->prefix;
391
392 apply_mask_ipv6 (&p);
393
394 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
395 return;
396
397 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
398
399 rib_update ();
400}
401
402void
403connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
hassofce954f2004-10-07 20:29:24 +0000404 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000405{
406 struct prefix_ipv6 p;
407 struct connected *ifc;
408
409 memset (&p, 0, sizeof (struct prefix_ipv6));
410 p.family = AF_INET6;
411 memcpy (&p.prefix, address, sizeof (struct in6_addr));
412 p.prefixlen = prefixlen;
413
paulca162182005-09-12 16:58:52 +0000414 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000415 if (! ifc)
416 return;
417
paulca162182005-09-12 16:58:52 +0000418 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000419}
420#endif /* HAVE_IPV6 */