blob: 7599d24dd61ba011fc280a99f57fb6f949a1204d [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);
54 else
55 connected_down_ipv6 (ifc->ifp, ifc);
56
57 UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
58 }
59
60 listnode_delete (ifc->ifp->connected, ifc);
61 connected_free (ifc);
62}
63
64static void
65connected_announce (struct interface *ifp, struct connected *ifc)
66{
67 if (!ifc)
68 return;
69
70 listnode_add (ifp->connected, ifc);
71
72 /* Update interface address information to protocol daemon. */
73 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
74 {
75 if (ifc->address->family == AF_INET)
76 if_subnet_add (ifp, ifc);
77
78 SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
79
80 zebra_interface_address_add_update (ifp, ifc);
81
82 if (if_is_up(ifp))
83 {
84 if (ifc->address->family == AF_INET)
85 connected_up_ipv4 (ifp, ifc);
86 else
87 connected_up_ipv6 (ifp, ifc);
88 }
89 }
90}
91
paul718e3742002-12-13 20:15:29 +000092/* If same interface address is already exist... */
93struct connected *
paulca162182005-09-12 16:58:52 +000094connected_check (struct interface *ifp, struct prefix *p)
paul718e3742002-12-13 20:15:29 +000095{
96 struct connected *ifc;
hasso52dc7ee2004-09-23 19:18:23 +000097 struct listnode *node;
paul718e3742002-12-13 20:15:29 +000098
paul1eb8ef22005-04-07 07:30:20 +000099 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
100 if (prefix_same (ifc->address, p))
101 return ifc;
paul718e3742002-12-13 20:15:29 +0000102
paul718e3742002-12-13 20:15:29 +0000103 return NULL;
104}
105
106/* Called from if_up(). */
107void
108connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
109{
110 struct prefix_ipv4 p;
111 struct prefix_ipv4 *addr;
112 struct prefix_ipv4 *dest;
113
114 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
115 return;
116
117 addr = (struct prefix_ipv4 *) ifc->address;
118 dest = (struct prefix_ipv4 *) ifc->destination;
119
120 memset (&p, 0, sizeof (struct prefix_ipv4));
121 p.family = AF_INET;
122 p.prefixlen = addr->prefixlen;
123
124 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000125 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000126 p.prefix = dest->prefix;
127 else
128 p.prefix = addr->prefix;
129
130 /* Apply mask to the network. */
131 apply_mask_ipv4 (&p);
132
133 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
134 address. */
135 if (prefix_ipv4_any (&p))
136 return;
137
138 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0);
139
140 rib_update ();
141}
142
143/* Add connected IPv4 route to the interface. */
144void
145connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
paula1ac18c2005-06-28 17:17:12 +0000146 u_char prefixlen, struct in_addr *broad, char *label)
paul718e3742002-12-13 20:15:29 +0000147{
148 struct prefix_ipv4 *p;
149 struct connected *ifc;
150 struct connected *current;
151
152 /* Make connected structure. */
153 ifc = connected_new ();
154 ifc->ifp = ifp;
155 ifc->flags = flags;
156
157 /* Allocate new connected address. */
158 p = prefix_ipv4_new ();
159 p->family = AF_INET;
160 p->prefix = *addr;
161 p->prefixlen = prefixlen;
162 ifc->address = (struct prefix *) p;
paulca162182005-09-12 16:58:52 +0000163
paul718e3742002-12-13 20:15:29 +0000164 /* If there is broadcast or pointopoint address. */
165 if (broad)
166 {
167 p = prefix_ipv4_new ();
168 p->family = AF_INET;
169 p->prefix = *broad;
170 ifc->destination = (struct prefix *) p;
hasso3fb9cd62004-10-19 19:44:43 +0000171
172 /* validate the destination address */
173 if (ifp->flags & IFF_POINTOPOINT)
174 {
175 if (IPV4_ADDR_SAME(addr,broad))
176 zlog_warn("warning: PtP interface %s has same local and peer "
177 "address %s, routing protocols may malfunction",
178 ifp->name,inet_ntoa(*addr));
179 else if ((prefixlen != IPV4_MAX_PREFIXLEN) &&
180 (ipv4_network_addr(addr->s_addr,prefixlen) !=
181 ipv4_network_addr(broad->s_addr,prefixlen)))
182 {
183 char buf[2][INET_ADDRSTRLEN];
184 zlog_warn("warning: PtP interface %s network mismatch: local "
185 "%s/%d vs. peer %s, routing protocols may malfunction",
186 ifp->name,
187 inet_ntop (AF_INET, addr, buf[0], sizeof(buf[0])),
188 prefixlen,
189 inet_ntop (AF_INET, broad, buf[1], sizeof(buf[1])));
190 }
191 }
192 else
193 {
194 if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
195 {
196 char buf[2][INET_ADDRSTRLEN];
197 struct in_addr bcalc;
198 bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
199 zlog_warn("warning: interface %s broadcast addr %s/%d != "
200 "calculated %s, routing protocols may malfunction",
201 ifp->name,
202 inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
203 prefixlen,
204 inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
205 }
206 }
207
paul718e3742002-12-13 20:15:29 +0000208 }
hasso3fb9cd62004-10-19 19:44:43 +0000209 else
210 /* no broadcast or destination address was supplied */
ajs341a8f12004-12-22 16:32:16 +0000211 if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
212 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
213 "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
paul718e3742002-12-13 20:15:29 +0000214
215 /* Label of this address. */
216 if (label)
217 ifc->label = strdup (label);
218
219 /* Check same connected route. */
paulca162182005-09-12 16:58:52 +0000220 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
221 connected_withdraw (current); /* implicit withdraw - freebsd does this */
222
223 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000224}
225
226void
227connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
228{
229 struct prefix_ipv4 p;
230 struct prefix_ipv4 *addr;
231 struct prefix_ipv4 *dest;
232
233 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
234 return;
235
236 addr = (struct prefix_ipv4 *)ifc->address;
237 dest = (struct prefix_ipv4 *)ifc->destination;
238
239 memset (&p, 0, sizeof (struct prefix_ipv4));
240 p.family = AF_INET;
241 p.prefixlen = addr->prefixlen;
242
paul960182a2003-04-09 07:16:04 +0000243 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000244 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000245 p.prefix = dest->prefix;
246 else
247 p.prefix = addr->prefix;
248
249 /* Apply mask to the network. */
250 apply_mask_ipv4 (&p);
251
252 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
253 address. */
254 if (prefix_ipv4_any (&p))
255 return;
256
257 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
258
259 rib_update ();
260}
261
262/* Delete connected IPv4 route to the interface. */
263void
264connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
paula1ac18c2005-06-28 17:17:12 +0000265 u_char prefixlen, struct in_addr *broad, char *label)
paul718e3742002-12-13 20:15:29 +0000266{
267 struct prefix_ipv4 p;
268 struct connected *ifc;
269
270 memset (&p, 0, sizeof (struct prefix_ipv4));
271 p.family = AF_INET;
272 p.prefix = *addr;
273 p.prefixlen = prefixlen;
274
paulca162182005-09-12 16:58:52 +0000275 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000276 if (! ifc)
277 return;
paulca162182005-09-12 16:58:52 +0000278
279 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000280}
281
282#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +0000283void
284connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
285{
286 struct prefix_ipv6 p;
287 struct prefix_ipv6 *addr;
288 struct prefix_ipv6 *dest;
289
290 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
291 return;
292
293 addr = (struct prefix_ipv6 *) ifc->address;
294 dest = (struct prefix_ipv6 *) ifc->destination;
295
296 memset (&p, 0, sizeof (struct prefix_ipv6));
297 p.family = AF_INET6;
298 p.prefixlen = addr->prefixlen;
299
paul31a476c2003-09-29 19:54:53 +0000300 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000301 {
302 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
303 p.prefix = addr->prefix;
304 else
305 p.prefix = dest->prefix;
306 }
307 else
308 p.prefix = addr->prefix;
309
310 /* Apply mask to the network. */
311 apply_mask_ipv6 (&p);
312
hasso726f9b22003-05-25 21:04:54 +0000313#if ! defined (MUSICA) && ! defined (LINUX)
314 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
paul718e3742002-12-13 20:15:29 +0000315 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
316 return;
hasso726f9b22003-05-25 21:04:54 +0000317#endif
paul718e3742002-12-13 20:15:29 +0000318
hassobe61c4e2005-08-27 06:05:47 +0000319 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +0000320
321 rib_update ();
322}
323
324/* Add connected IPv6 route to the interface. */
325void
326connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
hassofce954f2004-10-07 20:29:24 +0000327 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000328{
329 struct prefix_ipv6 *p;
330 struct connected *ifc;
331 struct connected *current;
332
333 /* Make connected structure. */
334 ifc = connected_new ();
335 ifc->ifp = ifp;
336
337 /* Allocate new connected address. */
338 p = prefix_ipv6_new ();
339 p->family = AF_INET6;
340 IPV6_ADDR_COPY (&p->prefix, addr);
341 p->prefixlen = prefixlen;
342 ifc->address = (struct prefix *) p;
343
344 /* If there is broadcast or pointopoint address. */
345 if (broad)
346 {
347 p = prefix_ipv6_new ();
348 p->family = AF_INET6;
349 IPV6_ADDR_COPY (&p->prefix, broad);
350 ifc->destination = (struct prefix *) p;
351 }
352
paulca162182005-09-12 16:58:52 +0000353 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
354 connected_withdraw (current); /* implicit update of existing address */
355
356 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000357}
358
359void
360connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
361{
362 struct prefix_ipv6 p;
363 struct prefix_ipv6 *addr;
364 struct prefix_ipv6 *dest;
365
366 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
367 return;
368
369 addr = (struct prefix_ipv6 *) ifc->address;
370 dest = (struct prefix_ipv6 *) ifc->destination;
371
372 memset (&p, 0, sizeof (struct prefix_ipv6));
373 p.family = AF_INET6;
374 p.prefixlen = addr->prefixlen;
375
paul31a476c2003-09-29 19:54:53 +0000376 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000377 {
378 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
379 p.prefix = addr->prefix;
380 else
381 p.prefix = dest->prefix;
382 }
383 else
384 p.prefix = addr->prefix;
385
386 apply_mask_ipv6 (&p);
387
388 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
389 return;
390
391 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
392
393 rib_update ();
394}
395
396void
397connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
hassofce954f2004-10-07 20:29:24 +0000398 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000399{
400 struct prefix_ipv6 p;
401 struct connected *ifc;
402
403 memset (&p, 0, sizeof (struct prefix_ipv6));
404 p.family = AF_INET6;
405 memcpy (&p.prefix, address, sizeof (struct in6_addr));
406 p.prefixlen = prefixlen;
407
paulca162182005-09-12 16:58:52 +0000408 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000409 if (! ifc)
410 return;
411
paulca162182005-09-12 16:58:52 +0000412 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000413}
414#endif /* HAVE_IPV6 */