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