and added files
[bcm963xx.git] / userapps / opensource / zebra / zebra / rt_socket.c
1 /*
2  * Kernel routing table updates by routing socket.
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 "if.h"
26 #include "prefix.h"
27 #include "sockunion.h"
28 #include "log.h"
29 #include "str.h"
30
31 #include "zebra/debug.h"
32 #include "zebra/rib.h"
33
34 int
35 rtm_write (int message,
36            union sockunion *dest,
37            union sockunion *mask,
38            union sockunion *gate,
39            unsigned int index,
40            int zebra_flags,
41            int metric);
42
43 /* Adjust netmask socket length. Return value is a adjusted sin_len
44    value. */
45 int
46 sin_masklen (struct in_addr mask)
47 {
48   char *p, *lim;
49   int len;
50   struct sockaddr_in sin;
51
52   if (mask.s_addr == 0) 
53     return sizeof (long);
54
55   sin.sin_addr = mask;
56   len = sizeof (struct sockaddr_in);
57
58   lim = (char *) &sin.sin_addr;
59   p = lim + sizeof (sin.sin_addr);
60
61   while (*--p == 0 && p >= lim) 
62     len--;
63   return len;
64 }
65
66 /* Interface between zebra message and rtm message. */
67 int
68 kernel_rtm_ipv4 (int cmd, struct prefix *p, struct rib *rib, int family)
69
70 {
71   struct sockaddr_in *mask;
72   struct sockaddr_in sin_dest, sin_mask, sin_gate;
73   struct nexthop *nexthop;
74   int nexthop_num = 0;
75   unsigned int ifindex = 0;
76   int gate = 0;
77   int error;
78
79   memset (&sin_dest, 0, sizeof (struct sockaddr_in));
80   sin_dest.sin_family = AF_INET;
81 #ifdef HAVE_SIN_LEN
82   sin_dest.sin_len = sizeof (struct sockaddr_in);
83 #endif /* HAVE_SIN_LEN */
84   sin_dest.sin_addr = p->u.prefix4;
85
86   memset (&sin_mask, 0, sizeof (struct sockaddr_in));
87
88   memset (&sin_gate, 0, sizeof (struct sockaddr_in));
89   sin_gate.sin_family = AF_INET;
90 #ifdef HAVE_SIN_LEN
91   sin_gate.sin_len = sizeof (struct sockaddr_in);
92 #endif /* HAVE_SIN_LEN */
93
94   /* Make gateway. */
95   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
96     {
97       gate = 0;
98
99       if ((cmd == RTM_ADD
100            && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
101           || (cmd == RTM_DELETE
102 #if 0
103               && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
104 #endif
105               ))
106         {
107           if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
108             {
109               if (nexthop->rtype == NEXTHOP_TYPE_IPV4 ||
110                   nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
111                 {
112                   sin_gate.sin_addr = nexthop->rgate.ipv4;
113                   gate = 1;
114                 }
115               if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
116                   || nexthop->rtype == NEXTHOP_TYPE_IFNAME
117                   || nexthop->rtype == NEXTHOP_TYPE_IPV4_IFINDEX)
118                 ifindex = nexthop->rifindex;
119             }
120           else
121             {
122               if (nexthop->type == NEXTHOP_TYPE_IPV4 ||
123                   nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
124                 {
125                   sin_gate.sin_addr = nexthop->gate.ipv4;
126                   gate = 1;
127                 }
128               if (nexthop->type == NEXTHOP_TYPE_IFINDEX
129                   || nexthop->type == NEXTHOP_TYPE_IFNAME
130                   || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX)
131                 ifindex = nexthop->ifindex;
132             }
133
134           if (cmd == RTM_ADD)
135             SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
136
137           if (gate && p->prefixlen == 32)
138             mask = NULL;
139           else
140             {
141               masklen2ip (p->prefixlen, &sin_mask.sin_addr);
142               sin_mask.sin_family = AF_UNSPEC;
143 #ifdef HAVE_SIN_LEN
144               sin_mask.sin_len = sin_masklen (sin_mask.sin_addr);
145 #endif /* HAVE_SIN_LEN */
146               mask = &sin_mask;
147             }
148         }
149
150       error = rtm_write (cmd,
151                         (union sockunion *)&sin_dest, 
152                         (union sockunion *)mask, 
153                         gate ? (union sockunion *)&sin_gate : NULL,
154                         ifindex,
155                         rib->flags,
156                         rib->metric);
157
158 #if 0
159       if (error)
160         {
161           zlog_info ("kernel_rtm_ipv4(): nexthop %d add error=%d.",
162             nexthop_num, error);
163         }
164 #endif
165
166       nexthop_num++;
167     }
168
169   /* If there is no useful nexthop then return. */
170   if (nexthop_num == 0)
171     {
172       if (IS_ZEBRA_DEBUG_KERNEL)
173         zlog_info ("kernel_rtm_ipv4(): No useful nexthop.");
174       return 0;
175     }
176
177   return 0; /*XXX*/
178 }
179
180 int
181 kernel_add_ipv4 (struct prefix *p, struct rib *rib)
182 {
183   return kernel_rtm_ipv4 (RTM_ADD, p, rib, AF_INET);
184 }
185
186 int
187 kernel_delete_ipv4 (struct prefix *p, struct rib *rib)
188 {
189   return kernel_rtm_ipv4 (RTM_DELETE, p, rib, AF_INET);
190 }
191
192 #ifdef HAVE_IPV6
193
194 /* Calculate sin6_len value for netmask socket value. */
195 int
196 sin6_masklen (struct in6_addr mask)
197 {
198   struct sockaddr_in6 sin6;
199   char *p, *lim;
200   int len;
201
202 #if defined (INRIA)
203   if (IN_ANYADDR6 (mask)) 
204     return sizeof (long);
205 #else /* ! INRIA */
206   if (IN6_IS_ADDR_UNSPECIFIED (&mask)) 
207     return sizeof (long);
208 #endif /* ! INRIA */
209
210   sin6.sin6_addr = mask;
211   len = sizeof (struct sockaddr_in6);
212
213   lim = (char *) & sin6.sin6_addr;
214   p = lim + sizeof (sin6.sin6_addr);
215
216   while (*--p == 0 && p >= lim) 
217     len--;
218
219   return len;
220 }
221
222 /* Interface between zebra message and rtm message. */
223 int
224 kernel_rtm_ipv6 (int message, struct prefix_ipv6 *dest,
225                  struct in6_addr *gate, int index, int flags)
226 {
227   struct sockaddr_in6 *mask;
228   struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
229
230   memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
231   sin_dest.sin6_family = AF_INET6;
232 #ifdef SIN6_LEN
233   sin_dest.sin6_len = sizeof (struct sockaddr_in6);
234 #endif /* SIN6_LEN */
235
236   memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
237
238   memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
239   sin_gate.sin6_family = AF_INET6;
240 #ifdef SIN6_LEN
241   sin_gate.sin6_len = sizeof (struct sockaddr_in6);
242 #endif /* SIN6_LEN */
243
244   sin_dest.sin6_addr = dest->prefix;
245
246   if (gate)
247     memcpy (&sin_gate.sin6_addr, gate, sizeof (struct in6_addr));
248
249   /* Under kame set interface index to link local address. */
250 #ifdef KAME
251
252 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
253   do { \
254     (a).s6_addr[2] = ((i) >> 8) & 0xff; \
255     (a).s6_addr[3] = (i) & 0xff; \
256   } while (0)
257
258   if (gate && IN6_IS_ADDR_LINKLOCAL(gate))
259     SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, index);
260 #endif /* KAME */
261
262   if (gate && dest->prefixlen == 128)
263     mask = NULL;
264   else
265     {
266       masklen2ip6 (dest->prefixlen, &sin_mask.sin6_addr);
267       sin_mask.sin6_family = AF_UNSPEC;
268 #ifdef SIN6_LEN
269       sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
270 #endif /* SIN6_LEN */
271       mask = &sin_mask;
272     }
273
274   return rtm_write (message, 
275                     (union sockunion *) &sin_dest,
276                     (union sockunion *) mask,
277                     gate ? (union sockunion *)&sin_gate : NULL,
278                     index,
279                     flags,
280                     0);
281 }
282
283 /* Interface between zebra message and rtm message. */
284 int
285 kernel_rtm_ipv6_multipath (int cmd, struct prefix *p, struct rib *rib,
286                            int family)
287 {
288   struct sockaddr_in6 *mask;
289   struct sockaddr_in6 sin_dest, sin_mask, sin_gate;
290   struct nexthop *nexthop;
291   int nexthop_num = 0;
292   unsigned int ifindex = 0;
293   int gate = 0;
294   int error;
295
296   memset (&sin_dest, 0, sizeof (struct sockaddr_in6));
297   sin_dest.sin6_family = AF_INET6;
298 #ifdef SIN6_LEN
299   sin_dest.sin6_len = sizeof (struct sockaddr_in6);
300 #endif /* SIN6_LEN */
301   sin_dest.sin6_addr = p->u.prefix6;
302
303   memset (&sin_mask, 0, sizeof (struct sockaddr_in6));
304
305   memset (&sin_gate, 0, sizeof (struct sockaddr_in6));
306   sin_gate.sin6_family = AF_INET6;
307 #ifdef HAVE_SIN_LEN
308   sin_gate.sin6_len = sizeof (struct sockaddr_in6);
309 #endif /* HAVE_SIN_LEN */
310
311   /* Make gateway. */
312   for (nexthop = rib->nexthop; nexthop; nexthop = nexthop->next)
313     {
314       gate = 0;
315
316       if ((cmd == RTM_ADD
317            && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_ACTIVE))
318           || (cmd == RTM_DELETE
319 #if 0
320               && CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB)
321 #endif
322               ))
323         {
324           if (CHECK_FLAG (nexthop->flags, NEXTHOP_FLAG_RECURSIVE))
325             {
326               if (nexthop->rtype == NEXTHOP_TYPE_IPV6
327                   || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
328                   || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
329                 {
330                   sin_gate.sin6_addr = nexthop->rgate.ipv6;
331                   gate = 1;
332                 }
333               if (nexthop->rtype == NEXTHOP_TYPE_IFINDEX
334                   || nexthop->rtype == NEXTHOP_TYPE_IFNAME
335                   || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFNAME
336                   || nexthop->rtype == NEXTHOP_TYPE_IPV6_IFINDEX)
337                 ifindex = nexthop->rifindex;
338             }
339           else
340             {
341               if (nexthop->type == NEXTHOP_TYPE_IPV6
342                   || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
343                   || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
344                 {
345                   sin_gate.sin6_addr = nexthop->gate.ipv6;
346                   gate = 1;
347                 }
348               if (nexthop->type == NEXTHOP_TYPE_IFINDEX
349                   || nexthop->type == NEXTHOP_TYPE_IFNAME
350                   || nexthop->type == NEXTHOP_TYPE_IPV6_IFNAME
351                   || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX)
352                 ifindex = nexthop->ifindex;
353             }
354
355           if (cmd == RTM_ADD)
356             SET_FLAG (nexthop->flags, NEXTHOP_FLAG_FIB);
357         }
358
359       /* Under kame set interface index to link local address. */
360 #ifdef KAME
361
362 #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \
363       do { \
364         (a).s6_addr[2] = ((i) >> 8) & 0xff; \
365         (a).s6_addr[3] = (i) & 0xff; \
366       } while (0)
367
368       if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr))
369         SET_IN6_LINKLOCAL_IFINDEX (sin_gate.sin6_addr, ifindex);
370 #endif /* KAME */
371
372       if (gate && p->prefixlen == 128)
373         mask = NULL;
374       else
375         {
376           masklen2ip6 (p->prefixlen, &sin_mask.sin6_addr);
377           sin_mask.sin6_family = AF_UNSPEC;
378 #ifdef SIN6_LEN
379           sin_mask.sin6_len = sin6_masklen (sin_mask.sin6_addr);
380 #endif /* SIN6_LEN */
381           mask = &sin_mask;
382         }
383
384       error = rtm_write (cmd,
385                         (union sockunion *) &sin_dest,
386                         (union sockunion *) mask,
387                         gate ? (union sockunion *)&sin_gate : NULL,
388                         ifindex,
389                         rib->flags,
390                         rib->metric);
391
392 #if 0
393       if (error)
394         {
395           zlog_info ("kernel_rtm_ipv6_multipath(): nexthop %d add error=%d.",
396             nexthop_num, error);
397         }
398 #endif
399
400       nexthop_num++;
401     }
402
403   /* If there is no useful nexthop then return. */
404   if (nexthop_num == 0)
405     {
406       if (IS_ZEBRA_DEBUG_KERNEL)
407         zlog_info ("kernel_rtm_ipv6_multipath(): No useful nexthop.");
408       return 0;
409     }
410
411   return 0; /*XXX*/
412 }
413
414 int
415 kernel_add_ipv6 (struct prefix *p, struct rib *rib)
416 {
417   return kernel_rtm_ipv6_multipath (RTM_ADD, p, rib, AF_INET6);
418 }
419
420 int
421 kernel_delete_ipv6 (struct prefix *p, struct rib *rib)
422 {
423   return kernel_rtm_ipv6_multipath (RTM_DELETE, p, rib, AF_INET6);
424 }
425
426 /* Delete IPv6 route from the kernel. */
427 int
428 kernel_delete_ipv6_old (struct prefix_ipv6 *dest, struct in6_addr *gate,
429                     int index, int flags, int table)
430 {
431   return kernel_rtm_ipv6 (RTM_DELETE, dest, gate, index, flags);
432 }
433 #endif /* HAVE_IPV6 */