+ sayonara old_pid!
[jleu-quagga.git] / zebra / connected.c
blob53aa25432fa4eb76c865f8231ff4c0e46fa54e27
1 /*
2 * Address linked list routine.
3 * Copyright (C) 1997, 98 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
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.
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.
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.
23 #include <zebra.h>
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 #include "memory.h"
34 #include "zebra/zserv.h"
35 #include "zebra/redistribute.h"
36 #include "zebra/interface.h"
37 #include "zebra/connected.h"
39 /* withdraw a connected address */
40 static void
41 connected_withdraw (struct connected *ifc)
43 if (! ifc)
44 return;
46 /* Update interface address information to protocol daemon. */
47 if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
49 zebra_interface_address_delete_update (ifc->ifp, ifc);
51 if_subnet_delete (ifc->ifp, ifc);
53 if (ifc->address->family == AF_INET)
54 connected_down_ipv4 (ifc->ifp, ifc);
55 #ifdef HAVE_IPV6
56 else
57 connected_down_ipv6 (ifc->ifp, ifc);
58 #endif
60 UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
63 if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
65 listnode_delete (ifc->ifp->connected, ifc);
66 connected_free (ifc);
70 static void
71 connected_announce (struct interface *ifp, struct connected *ifc)
73 if (!ifc)
74 return;
76 listnode_add (ifp->connected, ifc);
78 /* Update interface address information to protocol daemon. */
79 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
81 if (ifc->address->family == AF_INET)
82 if_subnet_add (ifp, ifc);
84 SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
86 zebra_interface_address_add_update (ifp, ifc);
88 if (if_is_up(ifp))
90 if (ifc->address->family == AF_INET)
91 connected_up_ipv4 (ifp, ifc);
92 #ifdef HAVE_IPV6
93 else
94 connected_up_ipv6 (ifp, ifc);
95 #endif
100 /* If same interface address is already exist... */
101 struct connected *
102 connected_check (struct interface *ifp, struct prefix *p)
104 struct connected *ifc;
105 struct listnode *node;
107 for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
108 if (prefix_same (ifc->address, p))
109 return ifc;
111 return NULL;
114 /* Check if two ifc's describe the same address */
115 static int
116 connected_same (struct connected *ifc1, struct connected *ifc2)
118 if (ifc1->ifp != ifc2->ifp)
119 return 0;
121 if (ifc1->destination)
122 if (!ifc2->destination)
123 return 0;
124 if (ifc2->destination)
125 if (!ifc1->destination)
126 return 0;
128 if (ifc1->destination && ifc2->destination)
129 if (!prefix_same (ifc1->destination, ifc2->destination))
130 return 0;
132 if (ifc1->flags != ifc2->flags)
133 return 0;
135 return 1;
138 /* Handle implicit withdrawals of addresses, where a system ADDs an address
139 * to an interface which already has the same address configured.
141 * Returns the struct connected which must be announced to clients,
142 * or NULL if nothing to do.
144 static struct connected *
145 connected_implicit_withdraw (struct interface *ifp, struct connected *ifc)
147 struct connected *current;
149 /* Check same connected route. */
150 if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
152 if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
153 SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
155 /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
156 * back an address we have already added.
158 if (connected_same (current, ifc) && CHECK_FLAG(current->conf, ZEBRA_IFC_REAL))
160 /* nothing to do */
161 connected_free (ifc);
162 return NULL;
165 UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
166 connected_withdraw (current); /* implicit withdraw - freebsd does this */
168 return ifc;
171 /* Called from if_up(). */
172 void
173 connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
175 struct prefix_ipv4 p;
177 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
178 return;
180 PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
182 /* Apply mask to the network. */
183 apply_mask_ipv4 (&p);
185 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
186 address. */
187 if (prefix_ipv4_any (&p))
188 return;
190 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
191 RT_TABLE_MAIN, ifp->metric, 0);
193 rib_update ();
196 /* Add connected IPv4 route to the interface. */
197 void
198 connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
199 u_char prefixlen, struct in_addr *broad,
200 const char *label)
202 struct prefix_ipv4 *p;
203 struct connected *ifc;
205 /* Make connected structure. */
206 ifc = connected_new ();
207 ifc->ifp = ifp;
208 ifc->flags = flags;
210 /* Allocate new connected address. */
211 p = prefix_ipv4_new ();
212 p->family = AF_INET;
213 p->prefix = *addr;
214 p->prefixlen = prefixlen;
215 ifc->address = (struct prefix *) p;
217 /* If there is broadcast or peer address. */
218 if (broad)
220 p = prefix_ipv4_new ();
221 p->family = AF_INET;
222 p->prefix = *broad;
223 p->prefixlen = prefixlen;
224 ifc->destination = (struct prefix *) p;
226 /* validate the destination address */
227 if (CONNECTED_PEER(ifc))
229 if (IPV4_ADDR_SAME(addr,broad))
230 zlog_warn("warning: interface %s has same local and peer "
231 "address %s, routing protocols may malfunction",
232 ifp->name,inet_ntoa(*addr));
234 else
236 if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
238 char buf[2][INET_ADDRSTRLEN];
239 struct in_addr bcalc;
240 bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
241 zlog_warn("warning: interface %s broadcast addr %s/%d != "
242 "calculated %s, routing protocols may malfunction",
243 ifp->name,
244 inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
245 prefixlen,
246 inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
251 else
253 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER))
255 zlog_warn("warning: %s called for interface %s "
256 "with peer flag set, but no peer address supplied",
257 __func__, ifp->name);
258 UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
261 /* no broadcast or destination address was supplied */
262 if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
263 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
264 "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
267 /* Label of this address. */
268 if (label)
269 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
271 /* nothing to do? */
272 if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
273 return;
275 connected_announce (ifp, ifc);
278 void
279 connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
281 struct prefix_ipv4 p;
283 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
284 return;
286 PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
288 /* Apply mask to the network. */
289 apply_mask_ipv4 (&p);
291 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
292 address. */
293 if (prefix_ipv4_any (&p))
294 return;
296 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
298 rib_update ();
301 /* Delete connected IPv4 route to the interface. */
302 void
303 connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
304 u_char prefixlen, struct in_addr *broad)
306 struct prefix_ipv4 p;
307 struct connected *ifc;
309 memset (&p, 0, sizeof (struct prefix_ipv4));
310 p.family = AF_INET;
311 p.prefix = *addr;
312 p.prefixlen = prefixlen;
314 ifc = connected_check (ifp, (struct prefix *) &p);
315 if (! ifc)
316 return;
318 connected_withdraw (ifc);
321 #ifdef HAVE_IPV6
322 void
323 connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
325 struct prefix_ipv6 p;
327 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
328 return;
330 PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
332 /* Apply mask to the network. */
333 apply_mask_ipv6 (&p);
335 #if ! defined (MUSICA) && ! defined (LINUX)
336 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
337 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
338 return;
339 #endif
341 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0,
342 ifp->metric, 0);
344 rib_update ();
347 /* Add connected IPv6 route to the interface. */
348 void
349 connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
350 u_char prefixlen, struct in6_addr *broad,
351 const char *label)
353 struct prefix_ipv6 *p;
354 struct connected *ifc;
356 /* Make connected structure. */
357 ifc = connected_new ();
358 ifc->ifp = ifp;
359 ifc->flags = flags;
361 /* Allocate new connected address. */
362 p = prefix_ipv6_new ();
363 p->family = AF_INET6;
364 IPV6_ADDR_COPY (&p->prefix, addr);
365 p->prefixlen = prefixlen;
366 ifc->address = (struct prefix *) p;
368 /* If there is broadcast or peer address. */
369 if (broad)
371 if (IN6_IS_ADDR_UNSPECIFIED(broad))
372 zlog_warn("warning: %s called for interface %s with unspecified "
373 "destination address; ignoring!", __func__, ifp->name);
374 else
376 p = prefix_ipv6_new ();
377 p->family = AF_INET6;
378 IPV6_ADDR_COPY (&p->prefix, broad);
379 p->prefixlen = prefixlen;
380 ifc->destination = (struct prefix *) p;
383 if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination)
385 zlog_warn("warning: %s called for interface %s "
386 "with peer flag set, but no peer address supplied",
387 __func__, ifp->name);
388 UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
391 /* Label of this address. */
392 if (label)
393 ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
395 if ((ifc = connected_implicit_withdraw (ifp, ifc)) == NULL)
396 return;
398 connected_announce (ifp, ifc);
401 void
402 connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
404 struct prefix_ipv6 p;
406 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
407 return;
409 PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
411 apply_mask_ipv6 (&p);
413 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
414 return;
416 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
418 rib_update ();
421 void
422 connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
423 u_char prefixlen, struct in6_addr *broad)
425 struct prefix_ipv6 p;
426 struct connected *ifc;
428 memset (&p, 0, sizeof (struct prefix_ipv6));
429 p.family = AF_INET6;
430 memcpy (&p.prefix, address, sizeof (struct in6_addr));
431 p.prefixlen = prefixlen;
433 ifc = connected_check (ifp, (struct prefix *) &p);
434 if (! ifc)
435 return;
437 connected_withdraw (ifc);
439 #endif /* HAVE_IPV6 */