Annotation of embedaddon/quagga/zebra/connected.c, revision 1.1.1.4
1.1 misho 1: /*
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: #include "memory.h"
33:
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;
1.1.1.4 ! misho 39:
! 40: /* communicate the withdrawal of a connected address */
1.1 misho 41: static void
42: connected_withdraw (struct connected *ifc)
43: {
44: if (! ifc)
45: return;
46:
47: /* Update interface address information to protocol daemon. */
48: if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
49: {
50: zebra_interface_address_delete_update (ifc->ifp, ifc);
51:
1.1.1.4 ! misho 52: if (ifc->address->family == AF_INET)
! 53: if_subnet_delete (ifc->ifp, ifc);
! 54:
1.1 misho 55: if (ifc->address->family == AF_INET)
56: connected_down_ipv4 (ifc->ifp, ifc);
57: #ifdef HAVE_IPV6
58: else
59: connected_down_ipv6 (ifc->ifp, ifc);
60: #endif
61:
62: UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
63: }
64:
1.1.1.4 ! misho 65: /* The address is not in the kernel anymore, so clear the flag */
! 66: UNSET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
! 67:
1.1 misho 68: if (!CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
69: {
70: listnode_delete (ifc->ifp->connected, ifc);
71: connected_free (ifc);
72: }
73: }
74:
75: static void
76: connected_announce (struct interface *ifp, struct connected *ifc)
77: {
78: if (!ifc)
79: return;
80:
81: listnode_add (ifp->connected, ifc);
82:
83: /* Update interface address information to protocol daemon. */
1.1.1.4 ! misho 84: if (ifc->address->family == AF_INET)
! 85: if_subnet_add (ifp, ifc);
1.1 misho 86:
1.1.1.4 ! misho 87: zebra_interface_address_add_update (ifp, ifc);
1.1 misho 88:
1.1.1.4 ! misho 89: if (if_is_operative(ifp))
! 90: {
! 91: if (ifc->address->family == AF_INET)
! 92: connected_up_ipv4 (ifp, ifc);
1.1 misho 93: #ifdef HAVE_IPV6
1.1.1.4 ! misho 94: else
! 95: connected_up_ipv6 (ifp, ifc);
1.1 misho 96: #endif
97: }
98: }
1.1.1.4 ! misho 99:
1.1 misho 100: /* If same interface address is already exist... */
101: struct connected *
102: connected_check (struct interface *ifp, struct prefix *p)
103: {
104: struct connected *ifc;
105: struct listnode *node;
106:
107: for (ALL_LIST_ELEMENTS_RO (ifp->connected, node, ifc))
108: if (prefix_same (ifc->address, p))
109: return ifc;
110:
111: return NULL;
112: }
113:
1.1.1.4 ! misho 114: /* Check if two ifc's describe the same address in the same state */
1.1 misho 115: static int
116: connected_same (struct connected *ifc1, struct connected *ifc2)
117: {
118: if (ifc1->ifp != ifc2->ifp)
119: return 0;
120:
121: if (ifc1->destination)
122: if (!ifc2->destination)
123: return 0;
124: if (ifc2->destination)
125: if (!ifc1->destination)
126: return 0;
127:
128: if (ifc1->destination && ifc2->destination)
129: if (!prefix_same (ifc1->destination, ifc2->destination))
130: return 0;
131:
132: if (ifc1->flags != ifc2->flags)
133: return 0;
1.1.1.4 ! misho 134:
! 135: if (ifc1->conf != ifc2->conf)
! 136: return 0;
1.1 misho 137:
138: return 1;
139: }
140:
1.1.1.4 ! misho 141: /* Handle changes to addresses and send the neccesary announcements
! 142: * to clients. */
! 143: static void
! 144: connected_update(struct interface *ifp, struct connected *ifc)
1.1 misho 145: {
146: struct connected *current;
147:
148: /* Check same connected route. */
149: if ((current = connected_check (ifp, (struct prefix *) ifc->address)))
150: {
151: if (CHECK_FLAG(current->conf, ZEBRA_IFC_CONFIGURED))
152: SET_FLAG(ifc->conf, ZEBRA_IFC_CONFIGURED);
153:
154: /* Avoid spurious withdraws, this might be just the kernel 'reflecting'
155: * back an address we have already added.
156: */
1.1.1.4 ! misho 157: if (connected_same (current, ifc))
1.1 misho 158: {
159: /* nothing to do */
160: connected_free (ifc);
1.1.1.4 ! misho 161: return;
1.1 misho 162: }
1.1.1.4 ! misho 163:
! 164: /* Clear the configured flag on the old ifc, so it will be freed by
! 165: * connected withdraw. */
1.1 misho 166: UNSET_FLAG(current->conf, ZEBRA_IFC_CONFIGURED);
167: connected_withdraw (current); /* implicit withdraw - freebsd does this */
168: }
1.1.1.4 ! misho 169:
! 170: /* If the connected is new or has changed, announce it, if it is usable */
! 171: if (CHECK_FLAG(ifc->conf, ZEBRA_IFC_REAL))
! 172: connected_announce(ifp, ifc);
1.1 misho 173: }
174:
175: /* Called from if_up(). */
176: void
177: connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
178: {
179: struct prefix_ipv4 p;
180:
181: if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
182: return;
183:
184: PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
185:
186: /* Apply mask to the network. */
187: apply_mask_ipv4 (&p);
188:
189: /* In case of connected address is 0.0.0.0/0 we treat it tunnel
190: address. */
191: if (prefix_ipv4_any (&p))
192: return;
193:
194: rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
1.1.1.4 ! misho 195: ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST);
1.1 misho 196:
1.1.1.3 misho 197: rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, NULL, ifp->ifindex,
1.1.1.4 ! misho 198: ifp->vrf_id, RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_MULTICAST);
1.1.1.3 misho 199:
1.1.1.4 ! misho 200: rib_update (ifp->vrf_id);
1.1 misho 201: }
202:
203: /* Add connected IPv4 route to the interface. */
204: void
205: connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
206: u_char prefixlen, struct in_addr *broad,
207: const char *label)
208: {
209: struct prefix_ipv4 *p;
210: struct connected *ifc;
211:
212: /* Make connected structure. */
213: ifc = connected_new ();
214: ifc->ifp = ifp;
215: ifc->flags = flags;
1.1.1.4 ! misho 216: /* If we get a notification from the kernel,
! 217: * we can safely assume the address is known to the kernel */
! 218: SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
1.1 misho 219:
220: /* Allocate new connected address. */
221: p = prefix_ipv4_new ();
222: p->family = AF_INET;
223: p->prefix = *addr;
224: p->prefixlen = prefixlen;
225: ifc->address = (struct prefix *) p;
226:
227: /* If there is broadcast or peer address. */
228: if (broad)
229: {
230: p = prefix_ipv4_new ();
231: p->family = AF_INET;
232: p->prefix = *broad;
233: p->prefixlen = prefixlen;
234: ifc->destination = (struct prefix *) p;
235:
236: /* validate the destination address */
237: if (CONNECTED_PEER(ifc))
238: {
239: if (IPV4_ADDR_SAME(addr,broad))
240: zlog_warn("warning: interface %s has same local and peer "
241: "address %s, routing protocols may malfunction",
242: ifp->name,inet_ntoa(*addr));
243: }
244: else
245: {
246: if (broad->s_addr != ipv4_broadcast_addr(addr->s_addr,prefixlen))
247: {
248: char buf[2][INET_ADDRSTRLEN];
249: struct in_addr bcalc;
250: bcalc.s_addr = ipv4_broadcast_addr(addr->s_addr,prefixlen);
251: zlog_warn("warning: interface %s broadcast addr %s/%d != "
252: "calculated %s, routing protocols may malfunction",
253: ifp->name,
254: inet_ntop (AF_INET, broad, buf[0], sizeof(buf[0])),
255: prefixlen,
256: inet_ntop (AF_INET, &bcalc, buf[1], sizeof(buf[1])));
257: }
258: }
259:
260: }
261: else
262: {
263: if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER))
264: {
265: zlog_warn("warning: %s called for interface %s "
266: "with peer flag set, but no peer address supplied",
267: __func__, ifp->name);
268: UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
269: }
270:
271: /* no broadcast or destination address was supplied */
272: if ((prefixlen == IPV4_MAX_PREFIXLEN) && if_is_pointopoint(ifp))
273: zlog_warn("warning: PtP interface %s with addr %s/%d needs a "
274: "peer address",ifp->name,inet_ntoa(*addr),prefixlen);
275: }
276:
277: /* Label of this address. */
278: if (label)
279: ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
280:
1.1.1.4 ! misho 281: /* For all that I know an IPv4 address is always ready when we receive
! 282: * the notification. So it should be safe to set the REAL flag here. */
! 283: SET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
! 284:
! 285: connected_update(ifp, ifc);
1.1 misho 286: }
287:
288: void
289: connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
290: {
291: struct prefix_ipv4 p;
292:
293: if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
294: return;
295:
296: PREFIX_COPY_IPV4(&p, CONNECTED_PREFIX(ifc));
297:
298: /* Apply mask to the network. */
299: apply_mask_ipv4 (&p);
300:
301: /* In case of connected address is 0.0.0.0/0 we treat it tunnel
302: address. */
303: if (prefix_ipv4_any (&p))
304: return;
305:
306: /* Same logic as for connected_up_ipv4(): push the changes into the head. */
1.1.1.4 ! misho 307: rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
! 308: SAFI_UNICAST);
1.1 misho 309:
1.1.1.4 ! misho 310: rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
! 311: SAFI_MULTICAST);
1.1.1.3 misho 312:
1.1.1.4 ! misho 313: rib_update (ifp->vrf_id);
1.1 misho 314: }
315:
316: /* Delete connected IPv4 route to the interface. */
317: void
318: connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
319: u_char prefixlen, struct in_addr *broad)
320: {
321: struct prefix_ipv4 p;
322: struct connected *ifc;
323:
324: memset (&p, 0, sizeof (struct prefix_ipv4));
325: p.family = AF_INET;
326: p.prefix = *addr;
327: p.prefixlen = prefixlen;
328:
329: ifc = connected_check (ifp, (struct prefix *) &p);
330: if (! ifc)
331: return;
332:
333: connected_withdraw (ifc);
334:
1.1.1.4 ! misho 335: rib_update (ifp->vrf_id);
1.1 misho 336: }
337:
338: #ifdef HAVE_IPV6
339: void
340: connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
341: {
342: struct prefix_ipv6 p;
343:
344: if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
345: return;
346:
347: PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
348:
349: /* Apply mask to the network. */
350: apply_mask_ipv6 (&p);
351:
1.1.1.4 ! misho 352: #ifndef LINUX
1.1 misho 353: /* XXX: It is already done by rib_bogus_ipv6 within rib_add_ipv6 */
354: if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
355: return;
356: #endif
357:
1.1.1.4 ! misho 358: rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
! 359: RT_TABLE_MAIN, ifp->metric, 0, 0, SAFI_UNICAST);
1.1 misho 360:
1.1.1.4 ! misho 361: rib_update (ifp->vrf_id);
1.1 misho 362: }
363:
364: /* Add connected IPv6 route to the interface. */
365: void
366: connected_add_ipv6 (struct interface *ifp, int flags, struct in6_addr *addr,
367: u_char prefixlen, struct in6_addr *broad,
368: const char *label)
369: {
370: struct prefix_ipv6 *p;
371: struct connected *ifc;
372:
373: /* Make connected structure. */
374: ifc = connected_new ();
375: ifc->ifp = ifp;
376: ifc->flags = flags;
1.1.1.4 ! misho 377: /* If we get a notification from the kernel,
! 378: * we can safely assume the address is known to the kernel */
! 379: SET_FLAG(ifc->conf, ZEBRA_IFC_QUEUED);
1.1 misho 380:
381: /* Allocate new connected address. */
382: p = prefix_ipv6_new ();
383: p->family = AF_INET6;
384: IPV6_ADDR_COPY (&p->prefix, addr);
385: p->prefixlen = prefixlen;
386: ifc->address = (struct prefix *) p;
387:
388: /* If there is broadcast or peer address. */
389: if (broad)
390: {
391: if (IN6_IS_ADDR_UNSPECIFIED(broad))
392: zlog_warn("warning: %s called for interface %s with unspecified "
393: "destination address; ignoring!", __func__, ifp->name);
394: else
395: {
396: p = prefix_ipv6_new ();
397: p->family = AF_INET6;
398: IPV6_ADDR_COPY (&p->prefix, broad);
399: p->prefixlen = prefixlen;
400: ifc->destination = (struct prefix *) p;
401: }
402: }
403: if (CHECK_FLAG(ifc->flags, ZEBRA_IFA_PEER) && !ifc->destination)
404: {
405: zlog_warn("warning: %s called for interface %s "
406: "with peer flag set, but no peer address supplied",
407: __func__, ifp->name);
408: UNSET_FLAG(ifc->flags, ZEBRA_IFA_PEER);
409: }
410:
411: /* Label of this address. */
412: if (label)
413: ifc->label = XSTRDUP (MTYPE_CONNECTED_LABEL, label);
1.1.1.4 ! misho 414:
! 415: /* On Linux, we only get here when DAD is complete, therefore we can set
! 416: * ZEBRA_IFC_REAL.
! 417: *
! 418: * On BSD, there currently doesn't seem to be a way to check for completion of
! 419: * DAD, so we replicate the old behaviour and set ZEBRA_IFC_REAL, although DAD
! 420: * might still be running.
! 421: */
! 422: SET_FLAG(ifc->conf, ZEBRA_IFC_REAL);
! 423: connected_update(ifp, ifc);
1.1 misho 424: }
425:
426: void
427: connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
428: {
429: struct prefix_ipv6 p;
430:
431: if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
432: return;
433:
434: PREFIX_COPY_IPV6(&p, CONNECTED_PREFIX(ifc));
435:
436: apply_mask_ipv6 (&p);
437:
438: if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
439: return;
440:
1.1.1.4 ! misho 441: rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, ifp->vrf_id,
! 442: SAFI_UNICAST);
1.1 misho 443:
1.1.1.4 ! misho 444: rib_update (ifp->vrf_id);
1.1 misho 445: }
446:
447: void
448: connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
449: u_char prefixlen, struct in6_addr *broad)
450: {
451: struct prefix_ipv6 p;
452: struct connected *ifc;
453:
454: memset (&p, 0, sizeof (struct prefix_ipv6));
455: p.family = AF_INET6;
456: memcpy (&p.prefix, address, sizeof (struct in6_addr));
457: p.prefixlen = prefixlen;
458:
459: ifc = connected_check (ifp, (struct prefix *) &p);
460: if (! ifc)
461: return;
462:
463: connected_withdraw (ifc);
464:
1.1.1.4 ! misho 465: rib_update (ifp->vrf_id);
1.1 misho 466: }
467: #endif /* HAVE_IPV6 */
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>