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