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