blob: 5557819c282e5a511bf509b3e800b7dfc2ded042 [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,
paula1ac18c2005-06-28 17:17:12 +0000150 u_char prefixlen, struct in_addr *broad, char *label)
paul718e3742002-12-13 20:15:29 +0000151{
152 struct prefix_ipv4 *p;
153 struct connected *ifc;
154 struct connected *current;
155
156 /* Make connected structure. */
157 ifc = connected_new ();
158 ifc->ifp = ifp;
159 ifc->flags = flags;
160
161 /* Allocate new connected address. */
162 p = prefix_ipv4_new ();
163 p->family = AF_INET;
164 p->prefix = *addr;
165 p->prefixlen = prefixlen;
166 ifc->address = (struct prefix *) p;
paulca162182005-09-12 16:58:52 +0000167
paul718e3742002-12-13 20:15:29 +0000168 /* If there is broadcast or pointopoint address. */
169 if (broad)
170 {
171 p = prefix_ipv4_new ();
172 p->family = AF_INET;
173 p->prefix = *broad;
174 ifc->destination = (struct prefix *) p;
hasso3fb9cd62004-10-19 19:44:43 +0000175
176 /* validate the destination address */
177 if (ifp->flags & IFF_POINTOPOINT)
178 {
179 if (IPV4_ADDR_SAME(addr,broad))
180 zlog_warn("warning: PtP interface %s has same local and peer "
181 "address %s, routing protocols may malfunction",
182 ifp->name,inet_ntoa(*addr));
183 else if ((prefixlen != IPV4_MAX_PREFIXLEN) &&
184 (ipv4_network_addr(addr->s_addr,prefixlen) !=
185 ipv4_network_addr(broad->s_addr,prefixlen)))
186 {
187 char buf[2][INET_ADDRSTRLEN];
188 zlog_warn("warning: PtP interface %s network mismatch: local "
189 "%s/%d vs. peer %s, routing protocols may malfunction",
190 ifp->name,
191 inet_ntop (AF_INET, addr, buf[0], sizeof(buf[0])),
192 prefixlen,
193 inet_ntop (AF_INET, broad, buf[1], sizeof(buf[1])));
194 }
195 }
196 else
197 {
198 if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
199 {
200 char buf[2][INET_ADDRSTRLEN];
201 struct in_addr bcalc;
202 bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
203 zlog_warn("warning: interface %s broadcast addr %s/%d != "
204 "calculated %s, routing protocols may malfunction",
205 ifp->name,
206 inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
207 prefixlen,
208 inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
209 }
210 }
211
paul718e3742002-12-13 20:15:29 +0000212 }
hasso3fb9cd62004-10-19 19:44:43 +0000213 else
214 /* no broadcast or destination address was supplied */
ajs341a8f12004-12-22 16:32:16 +0000215 if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
216 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
217 "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
paul718e3742002-12-13 20:15:29 +0000218
219 /* Label of this address. */
220 if (label)
221 ifc->label = strdup (label);
222
223 /* Check same connected route. */
paulca162182005-09-12 16:58:52 +0000224 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
225 connected_withdraw (current); /* implicit withdraw - freebsd does this */
226
227 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000228}
229
230void
231connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
232{
233 struct prefix_ipv4 p;
234 struct prefix_ipv4 *addr;
235 struct prefix_ipv4 *dest;
236
237 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
238 return;
239
240 addr = (struct prefix_ipv4 *)ifc->address;
241 dest = (struct prefix_ipv4 *)ifc->destination;
242
243 memset (&p, 0, sizeof (struct prefix_ipv4));
244 p.family = AF_INET;
245 p.prefixlen = addr->prefixlen;
246
paul960182a2003-04-09 07:16:04 +0000247 /* Point-to-point check. */
hasso3fb9cd62004-10-19 19:44:43 +0000248 if (CONNECTED_POINTOPOINT_HOST(ifc))
paul718e3742002-12-13 20:15:29 +0000249 p.prefix = dest->prefix;
250 else
251 p.prefix = addr->prefix;
252
253 /* Apply mask to the network. */
254 apply_mask_ipv4 (&p);
255
256 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
257 address. */
258 if (prefix_ipv4_any (&p))
259 return;
260
261 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
262
263 rib_update ();
264}
265
266/* Delete connected IPv4 route to the interface. */
267void
268connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
paula1ac18c2005-06-28 17:17:12 +0000269 u_char prefixlen, struct in_addr *broad, char *label)
paul718e3742002-12-13 20:15:29 +0000270{
271 struct prefix_ipv4 p;
272 struct connected *ifc;
273
274 memset (&p, 0, sizeof (struct prefix_ipv4));
275 p.family = AF_INET;
276 p.prefix = *addr;
277 p.prefixlen = prefixlen;
278
paulca162182005-09-12 16:58:52 +0000279 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000280 if (! ifc)
281 return;
paulca162182005-09-12 16:58:52 +0000282
283 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000284}
285
286#ifdef HAVE_IPV6
paul718e3742002-12-13 20:15:29 +0000287void
288connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
289{
290 struct prefix_ipv6 p;
291 struct prefix_ipv6 *addr;
292 struct prefix_ipv6 *dest;
293
294 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
295 return;
296
297 addr = (struct prefix_ipv6 *) ifc->address;
298 dest = (struct prefix_ipv6 *) ifc->destination;
299
300 memset (&p, 0, sizeof (struct prefix_ipv6));
301 p.family = AF_INET6;
302 p.prefixlen = addr->prefixlen;
303
paul31a476c2003-09-29 19:54:53 +0000304 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000305 {
306 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
307 p.prefix = addr->prefix;
308 else
309 p.prefix = dest->prefix;
310 }
311 else
312 p.prefix = addr->prefix;
313
314 /* Apply mask to the network. */
315 apply_mask_ipv6 (&p);
316
hasso726f9b22003-05-25 21:04:54 +0000317#if ! defined (MUSICA) && ! defined (LINUX)
318 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
paul718e3742002-12-13 20:15:29 +0000319 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
320 return;
hasso726f9b22003-05-25 21:04:54 +0000321#endif
paul718e3742002-12-13 20:15:29 +0000322
hassobe61c4e2005-08-27 06:05:47 +0000323 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0);
paul718e3742002-12-13 20:15:29 +0000324
325 rib_update ();
326}
327
328/* Add connected IPv6 route to the interface. */
329void
330connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
hassofce954f2004-10-07 20:29:24 +0000331 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000332{
333 struct prefix_ipv6 *p;
334 struct connected *ifc;
335 struct connected *current;
336
337 /* Make connected structure. */
338 ifc = connected_new ();
339 ifc->ifp = ifp;
340
341 /* Allocate new connected address. */
342 p = prefix_ipv6_new ();
343 p->family = AF_INET6;
344 IPV6_ADDR_COPY (&p->prefix, addr);
345 p->prefixlen = prefixlen;
346 ifc->address = (struct prefix *) p;
347
348 /* If there is broadcast or pointopoint address. */
349 if (broad)
350 {
351 p = prefix_ipv6_new ();
352 p->family = AF_INET6;
353 IPV6_ADDR_COPY (&p->prefix, broad);
354 ifc->destination = (struct prefix *) p;
355 }
356
paulca162182005-09-12 16:58:52 +0000357 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
358 connected_withdraw (current); /* implicit update of existing address */
359
360 connected_announce (ifp, ifc);
paul718e3742002-12-13 20:15:29 +0000361}
362
363void
364connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
365{
366 struct prefix_ipv6 p;
367 struct prefix_ipv6 *addr;
368 struct prefix_ipv6 *dest;
369
370 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
371 return;
372
373 addr = (struct prefix_ipv6 *) ifc->address;
374 dest = (struct prefix_ipv6 *) ifc->destination;
375
376 memset (&p, 0, sizeof (struct prefix_ipv6));
377 p.family = AF_INET6;
378 p.prefixlen = addr->prefixlen;
379
paul31a476c2003-09-29 19:54:53 +0000380 if (if_is_pointopoint (ifp) && dest)
paul718e3742002-12-13 20:15:29 +0000381 {
382 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
383 p.prefix = addr->prefix;
384 else
385 p.prefix = dest->prefix;
386 }
387 else
388 p.prefix = addr->prefix;
389
390 apply_mask_ipv6 (&p);
391
392 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
393 return;
394
395 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
396
397 rib_update ();
398}
399
400void
401connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
hassofce954f2004-10-07 20:29:24 +0000402 u_char prefixlen, struct in6_addr *broad)
paul718e3742002-12-13 20:15:29 +0000403{
404 struct prefix_ipv6 p;
405 struct connected *ifc;
406
407 memset (&p, 0, sizeof (struct prefix_ipv6));
408 p.family = AF_INET6;
409 memcpy (&p.prefix, address, sizeof (struct in6_addr));
410 p.prefixlen = prefixlen;
411
paulca162182005-09-12 16:58:52 +0000412 ifc = connected_check (ifp, (struct prefix *) &p);
paul718e3742002-12-13 20:15:29 +0000413 if (! ifc)
414 return;
415
paulca162182005-09-12 16:58:52 +0000416 connected_withdraw (ifc);
paul718e3742002-12-13 20:15:29 +0000417}
418#endif /* HAVE_IPV6 */