blob: 5d1c6b66735fafaae0262a734e913a1f29079cf1 [file] [log] [blame]
paul718e3742002-12-13 20:15:29 +00001/*
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
33#include "zebra/zserv.h"
34#include "zebra/redistribute.h"
35
36/* If same interface address is already exist... */
37struct connected *
38connected_check_ipv4 (struct interface *ifp, struct prefix *p)
39{
40 struct connected *ifc;
41 listnode node;
42
43 for (node = listhead (ifp->connected); node; node = nextnode (node))
44 {
45 ifc = getdata (node);
46
47 if (prefix_same (ifc->address, p))
48 return ifc;
49 }
50 return NULL;
51}
52
53/* Called from if_up(). */
54void
55connected_up_ipv4 (struct interface *ifp, struct connected *ifc)
56{
57 struct prefix_ipv4 p;
58 struct prefix_ipv4 *addr;
59 struct prefix_ipv4 *dest;
60
61 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
62 return;
63
64 addr = (struct prefix_ipv4 *) ifc->address;
65 dest = (struct prefix_ipv4 *) ifc->destination;
66
67 memset (&p, 0, sizeof (struct prefix_ipv4));
68 p.family = AF_INET;
69 p.prefixlen = addr->prefixlen;
70
71 /* Point-to-point check. */
paulf2c80652002-12-13 21:44:27 +000072 if (ifc_pointopoint (ifc) && dest)
paul718e3742002-12-13 20:15:29 +000073 p.prefix = dest->prefix;
74 else
75 p.prefix = addr->prefix;
76
77 /* Apply mask to the network. */
78 apply_mask_ipv4 (&p);
79
80 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
81 address. */
82 if (prefix_ipv4_any (&p))
83 return;
84
85 rib_add_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0, 0, 0);
86
87 rib_update ();
88}
89
90/* Add connected IPv4 route to the interface. */
91void
92connected_add_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
93 int prefixlen, struct in_addr *broad, char *label)
94{
95 struct prefix_ipv4 *p;
96 struct connected *ifc;
97 struct connected *current;
98
99 /* Make connected structure. */
100 ifc = connected_new ();
101 ifc->ifp = ifp;
102 ifc->flags = flags;
103
104 /* Allocate new connected address. */
105 p = prefix_ipv4_new ();
106 p->family = AF_INET;
107 p->prefix = *addr;
108 p->prefixlen = prefixlen;
109 ifc->address = (struct prefix *) p;
110
111 /* If there is broadcast or pointopoint address. */
112 if (broad)
113 {
114 p = prefix_ipv4_new ();
115 p->family = AF_INET;
116 p->prefix = *broad;
117 ifc->destination = (struct prefix *) p;
118 }
119
120 /* Label of this address. */
121 if (label)
122 ifc->label = strdup (label);
123
124 /* Check same connected route. */
125 current = connected_check_ipv4 (ifp, (struct prefix *) ifc->address);
126 if (current)
127 {
128 connected_free (ifc);
129 ifc = current;
130 }
131 else
132 {
133 listnode_add (ifp->connected, ifc);
134 }
135
136 /* Update interface address information to protocol daemon. */
137 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
138 {
139 SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
140
141 zebra_interface_address_add_update (ifp, ifc);
142
143 if (if_is_up(ifp))
144 connected_up_ipv4 (ifp, ifc);
145 }
146}
147
148void
149connected_down_ipv4 (struct interface *ifp, struct connected *ifc)
150{
151 struct prefix_ipv4 p;
152 struct prefix_ipv4 *addr;
153 struct prefix_ipv4 *dest;
154
155 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
156 return;
157
158 addr = (struct prefix_ipv4 *)ifc->address;
159 dest = (struct prefix_ipv4 *)ifc->destination;
160
161 memset (&p, 0, sizeof (struct prefix_ipv4));
162 p.family = AF_INET;
163 p.prefixlen = addr->prefixlen;
164
paul960182a2003-04-09 07:16:04 +0000165 /* Point-to-point check. */
166 if (dest && ifc_pointopoint (ifc))
paul718e3742002-12-13 20:15:29 +0000167 p.prefix = dest->prefix;
168 else
169 p.prefix = addr->prefix;
170
171 /* Apply mask to the network. */
172 apply_mask_ipv4 (&p);
173
174 /* In case of connected address is 0.0.0.0/0 we treat it tunnel
175 address. */
176 if (prefix_ipv4_any (&p))
177 return;
178
179 rib_delete_ipv4 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
180
181 rib_update ();
182}
183
184/* Delete connected IPv4 route to the interface. */
185void
186connected_delete_ipv4 (struct interface *ifp, int flags, struct in_addr *addr,
187 int prefixlen, struct in_addr *broad, char *label)
188{
189 struct prefix_ipv4 p;
190 struct connected *ifc;
191
192 memset (&p, 0, sizeof (struct prefix_ipv4));
193 p.family = AF_INET;
194 p.prefix = *addr;
195 p.prefixlen = prefixlen;
196
197 ifc = connected_check_ipv4 (ifp, (struct prefix *) &p);
198 if (! ifc)
199 return;
200
201 /* Update interface address information to protocol daemon. */
202 if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
203 {
204 zebra_interface_address_delete_update (ifp, ifc);
205
206 connected_down_ipv4 (ifp, ifc);
207
208 UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
209 }
210
211 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
212 {
213 listnode_delete (ifp->connected, ifc);
214 connected_free (ifc);
215 }
216}
217
218#ifdef HAVE_IPV6
219/* If same interface address is already exist... */
220struct connected *
221connected_check_ipv6 (struct interface *ifp, struct prefix *p)
222{
223 struct connected *ifc;
224 listnode node;
225
226 for (node = listhead (ifp->connected); node; node = nextnode (node))
227 {
228 ifc = getdata (node);
229
230 if (prefix_same (ifc->address, p))
231 return ifc;
232 }
233 return 0;
234}
235
236void
237connected_up_ipv6 (struct interface *ifp, struct connected *ifc)
238{
239 struct prefix_ipv6 p;
240 struct prefix_ipv6 *addr;
241 struct prefix_ipv6 *dest;
242
243 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
244 return;
245
246 addr = (struct prefix_ipv6 *) ifc->address;
247 dest = (struct prefix_ipv6 *) ifc->destination;
248
249 memset (&p, 0, sizeof (struct prefix_ipv6));
250 p.family = AF_INET6;
251 p.prefixlen = addr->prefixlen;
252
paul00df0c12002-12-13 21:07:36 +0000253 if (ifc_pointopoint (ifc) && dest)
paul718e3742002-12-13 20:15:29 +0000254 {
255 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
256 p.prefix = addr->prefix;
257 else
258 p.prefix = dest->prefix;
259 }
260 else
261 p.prefix = addr->prefix;
262
263 /* Apply mask to the network. */
264 apply_mask_ipv6 (&p);
265
266 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
267 return;
268
269 rib_add_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
270
271 rib_update ();
272}
273
274/* Add connected IPv6 route to the interface. */
275void
276connected_add_ipv6 (struct interface *ifp, struct in6_addr *addr,
277 int prefixlen, struct in6_addr *broad)
278{
279 struct prefix_ipv6 *p;
280 struct connected *ifc;
281 struct connected *current;
282
283 /* Make connected structure. */
284 ifc = connected_new ();
285 ifc->ifp = ifp;
286
287 /* Allocate new connected address. */
288 p = prefix_ipv6_new ();
289 p->family = AF_INET6;
290 IPV6_ADDR_COPY (&p->prefix, addr);
291 p->prefixlen = prefixlen;
292 ifc->address = (struct prefix *) p;
293
294 /* If there is broadcast or pointopoint address. */
295 if (broad)
296 {
297 p = prefix_ipv6_new ();
298 p->family = AF_INET6;
299 IPV6_ADDR_COPY (&p->prefix, broad);
300 ifc->destination = (struct prefix *) p;
301 }
302
303 current = connected_check_ipv6 (ifp, (struct prefix *) ifc->address);
304 if (current)
305 {
306 connected_free (ifc);
307 ifc = current;
308 }
309 else
310 {
311 listnode_add (ifp->connected, ifc);
312 }
313
314 /* Update interface address information to protocol daemon. */
315 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
316 {
317 SET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
318
319 zebra_interface_address_add_update (ifp, ifc);
320
321 if (if_is_up(ifp))
322 connected_up_ipv6 (ifp, ifc);
323 }
324}
325
326void
327connected_down_ipv6 (struct interface *ifp, struct connected *ifc)
328{
329 struct prefix_ipv6 p;
330 struct prefix_ipv6 *addr;
331 struct prefix_ipv6 *dest;
332
333 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
334 return;
335
336 addr = (struct prefix_ipv6 *) ifc->address;
337 dest = (struct prefix_ipv6 *) ifc->destination;
338
339 memset (&p, 0, sizeof (struct prefix_ipv6));
340 p.family = AF_INET6;
341 p.prefixlen = addr->prefixlen;
342
paul00df0c12002-12-13 21:07:36 +0000343 if (ifc_pointopoint (ifc) && dest)
paul718e3742002-12-13 20:15:29 +0000344 {
345 if (IN6_IS_ADDR_UNSPECIFIED (&dest->prefix))
346 p.prefix = addr->prefix;
347 else
348 p.prefix = dest->prefix;
349 }
350 else
351 p.prefix = addr->prefix;
352
353 apply_mask_ipv6 (&p);
354
355 if (IN6_IS_ADDR_UNSPECIFIED (&p.prefix))
356 return;
357
358 rib_delete_ipv6 (ZEBRA_ROUTE_CONNECT, 0, &p, NULL, ifp->ifindex, 0);
359
360 rib_update ();
361}
362
363void
364connected_delete_ipv6 (struct interface *ifp, struct in6_addr *address,
365 int prefixlen, struct in6_addr *broad)
366{
367 struct prefix_ipv6 p;
368 struct connected *ifc;
369
370 memset (&p, 0, sizeof (struct prefix_ipv6));
371 p.family = AF_INET6;
372 memcpy (&p.prefix, address, sizeof (struct in6_addr));
373 p.prefixlen = prefixlen;
374
375 ifc = connected_check_ipv6 (ifp, (struct prefix *) &p);
376 if (! ifc)
377 return;
378
379 /* Update interface address information to protocol daemon. */
380 if (CHECK_FLAG (ifc->conf, ZEBRA_IFC_REAL))
381 {
382 zebra_interface_address_delete_update (ifp, ifc);
383
384 connected_down_ipv6 (ifp, ifc);
385
386 UNSET_FLAG (ifc->conf, ZEBRA_IFC_REAL);
387 }
388
389 if (! CHECK_FLAG (ifc->conf, ZEBRA_IFC_CONFIGURED))
390 {
391 listnode_delete (ifp->connected, ifc);
392 connected_free (ifc);
393 }
394}
395#endif /* HAVE_IPV6 */