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
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
34 #include "zebra/zserv.h"
35 #include "zebra/redistribute.h"
36 #include "zebra/interface.h"
37 #include "zebra/connected.h"
38 extern struct zebra_t zebrad
;
40 /* withdraw a connected address */
42 connected_withdraw (struct connected
*ifc
)
47 /* Update interface address information to protocol daemon. */
48 if (CHECK_FLAG (ifc
->conf
, ZEBRA_IFC_REAL
))
50 zebra_interface_address_delete_update (ifc
->ifp
, ifc
);
52 if_subnet_delete (ifc
->ifp
, ifc
);
54 if (ifc
->address
->family
== AF_INET
)
55 connected_down_ipv4 (ifc
->ifp
, ifc
);
58 connected_down_ipv6 (ifc
->ifp
, ifc
);
61 UNSET_FLAG (ifc
->conf
, ZEBRA_IFC_REAL
);
64 if (!CHECK_FLAG (ifc
->conf
, ZEBRA_IFC_CONFIGURED
))
66 listnode_delete (ifc
->ifp
->connected
, ifc
);
72 connected_announce (struct interface
*ifp
, struct connected
*ifc
)
77 listnode_add (ifp
->connected
, ifc
);
79 /* Update interface address information to protocol daemon. */
80 if (! CHECK_FLAG (ifc
->conf
, ZEBRA_IFC_REAL
))
82 if (ifc
->address
->family
== AF_INET
)
83 if_subnet_add (ifp
, ifc
);
85 SET_FLAG (ifc
->conf
, ZEBRA_IFC_REAL
);
87 zebra_interface_address_add_update (ifp
, ifc
);
89 if (if_is_operative(ifp
))
91 if (ifc
->address
->family
== AF_INET
)
92 connected_up_ipv4 (ifp
, ifc
);
95 connected_up_ipv6 (ifp
, ifc
);
101 /* If same interface address is already exist... */
103 connected_check (struct interface
*ifp
, struct prefix
*p
)
105 struct connected
*ifc
;
106 struct listnode
*node
;
108 for (ALL_LIST_ELEMENTS_RO (ifp
->connected
, node
, ifc
))
109 if (prefix_same (ifc
->address
, p
))
115 /* Check if two ifc's describe the same address */
117 connected_same (struct connected
*ifc1
, struct connected
*ifc2
)
119 if (ifc1
->ifp
!= ifc2
->ifp
)
122 if (ifc1
->destination
)
123 if (!ifc2
->destination
)
125 if (ifc2
->destination
)
126 if (!ifc1
->destination
)
129 if (ifc1
->destination
&& ifc2
->destination
)
130 if (!prefix_same (ifc1
->destination
, ifc2
->destination
))
133 if (ifc1
->flags
!= ifc2
->flags
)
139 /* Handle implicit withdrawals of addresses, where a system ADDs an address
140 * to an interface which already has the same address configured.
142 * Returns the struct connected which must be announced to clients,
143 * or NULL if nothing to do.
145 static struct connected
*
146 connected_implicit_withdraw (struct interface
*ifp
, struct connected
*ifc
)
148 struct connected
*current
;
150 /* Check same connected route. */
151 if ((current
= connected_check (ifp
, (struct prefix
*) ifc
->address
)))
153 if (CHECK_FLAG(current
->conf
, ZEBRA_IFC_CONFIGURED
))
154 SET_FLAG(ifc
->conf
, ZEBRA_IFC_CONFIGURED
);
156 /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
157 * back an address we have already added.
159 if (connected_same (current
, ifc
) && CHECK_FLAG(current
->conf
, ZEBRA_IFC_REAL
))
162 connected_free (ifc
);
166 UNSET_FLAG(current
->conf
, ZEBRA_IFC_CONFIGURED
);
167 connected_withdraw (current
); /* implicit withdraw - freebsd does this */
172 /* Called from if_up(). */
174 connected_up_ipv4 (struct interface
*ifp
, struct connected
*ifc
)
176 struct prefix_ipv4 p
;
178 if (! CHECK_FLAG (ifc
->conf
, ZEBRA_IFC_REAL
))
181 PREFIX_COPY_IPV4(&p
, CONNECTED_PREFIX(ifc
));
183 /* Apply mask to the network. */
184 apply_mask_ipv4 (&p
);
186 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
188 if (prefix_ipv4_any (&p
))
191 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT
, 0, &p
, NULL
, NULL
, ifp
->ifindex
,
192 RT_TABLE_MAIN
, ifp
->metric
, 0);
197 /* Add connected IPv4 route to the interface. */
199 connected_add_ipv4 (struct interface
*ifp
, int flags
, struct in_addr
*addr
,
200 u_char prefixlen
, struct in_addr
*broad
,
203 struct prefix_ipv4
*p
;
204 struct connected
*ifc
;
206 /* Make connected structure. */
207 ifc
= connected_new ();
211 /* Allocate new connected address. */
212 p
= prefix_ipv4_new ();
215 p
->prefixlen
= prefixlen
;
216 ifc
->address
= (struct prefix
*) p
;
218 /* If there is broadcast or peer address. */
221 p
= prefix_ipv4_new ();
224 p
->prefixlen
= prefixlen
;
225 ifc
->destination
= (struct prefix
*) p
;
227 /* validate the destination address */
228 if (CONNECTED_PEER(ifc
))
230 if (IPV4_ADDR_SAME(addr
,broad
))
231 zlog_warn("warning: interface %s has same local and peer "
232 "address %s, routing protocols may malfunction",
233 ifp
->name
,inet_ntoa(*addr
));
237 if (broad
->s_addr
!= ipv4_broadcast_addr(addr
->s_addr
,prefixlen
))
239 char buf
[2][INET_ADDRSTRLEN
];
240 struct in_addr bcalc
;
241 bcalc
.s_addr
= ipv4_broadcast_addr(addr
->s_addr
,prefixlen
);
242 zlog_warn("warning: interface %s broadcast addr %s/%d != "
243 "calculated %s, routing protocols may malfunction",
245 inet_ntop (AF_INET
, broad
, buf
[0], sizeof(buf
[0])),
247 inet_ntop (AF_INET
, &bcalc
, buf
[1], sizeof(buf
[1])));
254 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_PEER
))
256 zlog_warn("warning: %s called for interface %s "
257 "with peer flag set, but no peer address supplied",
258 __func__
, ifp
->name
);
259 UNSET_FLAG(ifc
->flags
, ZEBRA_IFA_PEER
);
262 /* no broadcast or destination address was supplied */
263 if ((prefixlen
== IPV4_MAX_PREFIXLEN
) && if_is_pointopoint(ifp
))
264 zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
265 "peer address",ifp
->name
,inet_ntoa(*addr
),prefixlen
);
268 /* Label of this address. */
270 ifc
->label
= XSTRDUP (MTYPE_CONNECTED_LABEL
, label
);
273 if ((ifc
= connected_implicit_withdraw (ifp
, ifc
)) == NULL
)
276 connected_announce (ifp
, ifc
);
280 connected_down_ipv4 (struct interface
*ifp
, struct connected
*ifc
)
282 struct prefix_ipv4 p
;
284 if (! CHECK_FLAG (ifc
->conf
, ZEBRA_IFC_REAL
))
287 PREFIX_COPY_IPV4(&p
, CONNECTED_PREFIX(ifc
));
289 /* Apply mask to the network. */
290 apply_mask_ipv4 (&p
);
292 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
294 if (prefix_ipv4_any (&p
))
297 /* Same logic as for connected_up_ipv4(): push the changes into the head. */
298 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT
, 0, &p
, NULL
, ifp
->ifindex
, 0);
303 /* Delete connected IPv4 route to the interface. */
305 connected_delete_ipv4 (struct interface
*ifp
, int flags
, struct in_addr
*addr
,
306 u_char prefixlen
, struct in_addr
*broad
)
308 struct prefix_ipv4 p
;
309 struct connected
*ifc
;
311 memset (&p
, 0, sizeof (struct prefix_ipv4
));
314 p
.prefixlen
= prefixlen
;
316 ifc
= connected_check (ifp
, (struct prefix
*) &p
);
320 connected_withdraw (ifc
);
327 connected_up_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
329 struct prefix_ipv6 p
;
331 if (! CHECK_FLAG (ifc
->conf
, ZEBRA_IFC_REAL
))
334 PREFIX_COPY_IPV6(&p
, CONNECTED_PREFIX(ifc
));
336 /* Apply mask to the network. */
337 apply_mask_ipv6 (&p
);
339 #if ! defined (MUSICA) && ! defined (LINUX)
340 /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
341 if (IN6_IS_ADDR_UNSPECIFIED (&p
.prefix
))
345 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT
, 0, &p
, NULL
, ifp
->ifindex
, RT_TABLE_MAIN
,
351 /* Add connected IPv6 route to the interface. */
353 connected_add_ipv6 (struct interface
*ifp
, int flags
, struct in6_addr
*addr
,
354 u_char prefixlen
, struct in6_addr
*broad
,
357 struct prefix_ipv6
*p
;
358 struct connected
*ifc
;
360 /* Make connected structure. */
361 ifc
= connected_new ();
365 /* Allocate new connected address. */
366 p
= prefix_ipv6_new ();
367 p
->family
= AF_INET6
;
368 IPV6_ADDR_COPY (&p
->prefix
, addr
);
369 p
->prefixlen
= prefixlen
;
370 ifc
->address
= (struct prefix
*) p
;
372 /* If there is broadcast or peer address. */
375 if (IN6_IS_ADDR_UNSPECIFIED(broad
))
376 zlog_warn("warning: %s called for interface %s with unspecified "
377 "destination address; ignoring!", __func__
, ifp
->name
);
380 p
= prefix_ipv6_new ();
381 p
->family
= AF_INET6
;
382 IPV6_ADDR_COPY (&p
->prefix
, broad
);
383 p
->prefixlen
= prefixlen
;
384 ifc
->destination
= (struct prefix
*) p
;
387 if (CHECK_FLAG(ifc
->flags
, ZEBRA_IFA_PEER
) && !ifc
->destination
)
389 zlog_warn("warning: %s called for interface %s "
390 "with peer flag set, but no peer address supplied",
391 __func__
, ifp
->name
);
392 UNSET_FLAG(ifc
->flags
, ZEBRA_IFA_PEER
);
395 /* Label of this address. */
397 ifc
->label
= XSTRDUP (MTYPE_CONNECTED_LABEL
, label
);
399 if ((ifc
= connected_implicit_withdraw (ifp
, ifc
)) == NULL
)
402 connected_announce (ifp
, ifc
);
406 connected_down_ipv6 (struct interface
*ifp
, struct connected
*ifc
)
408 struct prefix_ipv6 p
;
410 if (! CHECK_FLAG (ifc
->conf
, ZEBRA_IFC_REAL
))
413 PREFIX_COPY_IPV6(&p
, CONNECTED_PREFIX(ifc
));
415 apply_mask_ipv6 (&p
);
417 if (IN6_IS_ADDR_UNSPECIFIED (&p
.prefix
))
420 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT
, 0, &p
, NULL
, ifp
->ifindex
, 0);
426 connected_delete_ipv6 (struct interface
*ifp
, struct in6_addr
*address
,
427 u_char prefixlen
, struct in6_addr
*broad
)
429 struct prefix_ipv6 p
;
430 struct connected
*ifc
;
432 memset (&p
, 0, sizeof (struct prefix_ipv6
));
434 memcpy (&p
.prefix
, address
, sizeof (struct in6_addr
));
435 p
.prefixlen
= prefixlen
;
437 ifc
= connected_check (ifp
, (struct prefix
*) &p
);
441 connected_withdraw (ifc
);
445 #endif /* HAVE_IPV6 */