2 * Prefix related functions.
3 * Copyright (C) 1997, 98, 99 Kunihiro Ishiguro
5 * This file is part of GNU Zebra.
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
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.
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
27 #include "sockunion.h"
32 static u_char maskbit
[] = {0x00, 0x80, 0xc0, 0xe0, 0xf0,
33 0xf8, 0xfc, 0xfe, 0xff};
35 /* Number of bits in prefix type. */
40 #define MASKBIT(offset) ((0xff << (PNBBY - (offset))) & 0xff)
42 /* Address Famiy Identifier to Address Family converter. */
49 else if (afi
== AFI_IP6
)
51 #endif /* HAVE_IPV6 */
56 family2afi (int family
)
58 if (family
== AF_INET
)
61 else if (family
== AF_INET6
)
63 #endif /* HAVE_IPV6 */
67 /* If n includes p prefix then return 1 else return 0. */
69 prefix_match (struct prefix
*n
, struct prefix
*p
)
74 /* Set both prefix's head pointer. */
75 u_char
*np
= (u_char
*)&n
->u
.prefix
;
76 u_char
*pp
= (u_char
*)&p
->u
.prefix
;
78 /* If n's prefix is longer than p's one return 0. */
79 if (n
->prefixlen
> p
->prefixlen
)
82 offset
= n
->prefixlen
/ PNBBY
;
83 shift
= n
->prefixlen
% PNBBY
;
86 if (maskbit
[shift
] & (np
[offset
] ^ pp
[offset
]))
90 if (np
[offset
] != pp
[offset
])
95 /* Copy prefix from src to dest. */
97 prefix_copy (struct prefix
*dest
, struct prefix
*src
)
99 dest
->family
= src
->family
;
100 dest
->prefixlen
= src
->prefixlen
;
102 if (src
->family
== AF_INET
)
103 dest
->u
.prefix4
= src
->u
.prefix4
;
105 else if (src
->family
== AF_INET6
)
106 dest
->u
.prefix6
= src
->u
.prefix6
;
107 #endif /* HAVE_IPV6 */
108 else if (src
->family
== AF_UNSPEC
)
110 dest
->u
.lp
.id
= src
->u
.lp
.id
;
111 dest
->u
.lp
.adv_router
= src
->u
.lp
.adv_router
;
115 zlog (NULL
, LOG_INFO
, "prefix_copy(): Unknown address family %d",
121 /* If both prefix structure is same then return 1 else return 0. */
123 prefix_same (struct prefix
*p1
, struct prefix
*p2
)
125 if (p1
->family
== p2
->family
&& p1
->prefixlen
== p2
->prefixlen
)
127 if (p1
->family
== AF_INET
)
128 if (IPV4_ADDR_SAME (&p1
->u
.prefix
, &p2
->u
.prefix
))
131 if (p1
->family
== AF_INET6
)
132 if (IPV6_ADDR_SAME (&p1
->u
.prefix
, &p2
->u
.prefix
))
134 #endif /* HAVE_IPV6 */
139 /* When both prefix structure is not same, but will be same after
140 applying mask, return 0. otherwise, return 1 */
142 prefix_cmp (struct prefix
*p1
, struct prefix
*p2
)
147 /* Set both prefix's head pointer. */
148 u_char
*pp1
= (u_char
*)&p1
->u
.prefix
;
149 u_char
*pp2
= (u_char
*)&p2
->u
.prefix
;
151 if (p1
->family
!= p2
->family
|| p1
->prefixlen
!= p2
->prefixlen
)
154 offset
= p1
->prefixlen
/ 8;
155 shift
= p1
->prefixlen
% 8;
158 if (maskbit
[shift
] & (pp1
[offset
] ^ pp2
[offset
]))
162 if (pp1
[offset
] != pp2
[offset
])
168 /* Return prefix family type string. */
170 prefix_family_str (struct prefix
*p
)
172 if (p
->family
== AF_INET
)
175 if (p
->family
== AF_INET6
)
177 #endif /* HAVE_IPV6 */
181 /* Allocate new prefix_ipv4 structure. */
185 struct prefix_ipv4
*p
;
187 p
= XMALLOC (MTYPE_PREFIX_IPV4
, sizeof *p
);
188 bzero (p
, sizeof (struct prefix_ipv4
));
193 /* Free prefix_ipv4 structure. */
195 prefix_ipv4_free (struct prefix_ipv4
*p
)
197 XFREE (MTYPE_PREFIX_IPV4
, p
);
200 /* When string format is invalid return 0. */
202 str2prefix_ipv4 (char *str
, struct prefix_ipv4
*p
)
209 /* Find slash inside string. */
210 pnt
= strchr (str
, '/');
212 /* String doesn't contail slash. */
215 /* Convert string to prefix. */
216 ret
= inet_aton (str
, &p
->prefix
);
220 /* If address doesn't contain slash we assume it host address. */
222 p
->prefixlen
= IPV4_MAX_BITLEN
;
228 cp
= XMALLOC (MTYPE_TMP
, (pnt
- str
) + 1);
229 strncpy (cp
, str
, pnt
- str
);
230 *(cp
+ (pnt
- str
)) = '\0';
231 ret
= inet_aton (cp
, &p
->prefix
);
232 XFREE (MTYPE_TMP
, cp
);
234 /* Get prefix length. */
235 plen
= (u_char
) atoi (++pnt
);
246 /* Convert masklen into IP address's netmask. */
248 masklen2ip (int masklen
, struct in_addr
*netmask
)
254 bzero (netmask
, sizeof (struct in_addr
));
255 pnt
= (unsigned char *) netmask
;
257 offset
= masklen
/ 8;
267 /* Convert IP address's netmask into integer. We assume netmask is
268 sequential one. Argument netmask should be network byte order. */
270 ip_masklen (struct in_addr netmask
)
278 pnt
= (u_char
*) &netmask
;
281 while ((*pnt
== 0xff) && pnt
< end
)
299 /* Apply mask to IPv4 prefix. */
301 apply_mask_ipv4 (struct prefix_ipv4
*p
)
307 index
= p
->prefixlen
/ 8;
311 pnt
= (u_char
*) &p
->prefix
;
312 offset
= p
->prefixlen
% 8;
314 pnt
[index
] &= maskbit
[offset
];
322 /* If prefix is 0.0.0.0/0 then return 1 else return 0. */
324 prefix_ipv4_any (struct prefix_ipv4
*p
)
326 return (p
->prefix
.s_addr
== 0 && p
->prefixlen
== 0);
331 /* Allocate a new ip version 6 route */
335 struct prefix_ipv6
*p
;
337 p
= XMALLOC (MTYPE_PREFIX_IPV6
, sizeof (struct prefix_ipv6
));
338 bzero (p
, sizeof (struct prefix_ipv6
));
339 p
->family
= AF_INET6
;
343 /* Free prefix for IPv6. */
345 prefix_ipv6_free (struct prefix_ipv6
*p
)
347 XFREE (MTYPE_PREFIX_IPV6
, p
);
350 /* If given string is valid return pin6 else return NULL */
352 str2prefix_ipv6 (char *str
, struct prefix_ipv6
*p
)
358 pnt
= strchr (str
, '/');
360 /* If string doesn't contain `/' treat it as host route. */
363 ret
= inet_pton (AF_INET6
, str
, &p
->prefix
);
366 p
->prefixlen
= IPV6_MAX_BITLEN
;
372 cp
= XMALLOC (0, (pnt
- str
) + 1);
373 strncpy (cp
, str
, pnt
- str
);
374 *(cp
+ (pnt
- str
)) = '\0';
375 ret
= inet_pton (AF_INET6
, cp
, &p
->prefix
);
379 plen
= (u_char
) atoi (++pnt
);
384 p
->family
= AF_INET6
;
389 /* Convert struct in6_addr netmask into integer. */
391 ip6_masklen (struct in6_addr netmask
)
397 pnt
= (unsigned char *) & netmask
;
399 while ((*pnt
== 0xff) && len
< 128)
418 masklen2ip6 (int masklen
, struct in6_addr
*netmask
)
424 bzero (netmask
, sizeof (struct in6_addr
));
425 pnt
= (unsigned char *) netmask
;
427 offset
= masklen
/ 8;
438 apply_mask_ipv6 (struct prefix_ipv6
*p
)
444 index
= p
->prefixlen
/ 8;
448 pnt
= (u_char
*) &p
->prefix
;
449 offset
= p
->prefixlen
% 8;
451 pnt
[index
] &= maskbit
[offset
];
460 str2in6_addr (char *str
, struct in6_addr
*addr
)
465 /* %x must point to unsinged int */
466 for (i
= 0; i
< 16; i
++)
468 sscanf (str
+ (i
* 2), "%02x", &x
);
469 addr
->s6_addr
[i
] = x
& 0xff;
472 #endif /* HAVE_IPV6 */
475 apply_mask (struct prefix
*p
)
480 apply_mask_ipv4 ((struct prefix_ipv4
*)p
);
484 apply_mask_ipv6 ((struct prefix_ipv6
*)p
);
486 #endif /* HAVE_IPV6 */
493 /* Utility function of convert between struct prefix <=> union sockunion */
495 sockunion2prefix (union sockunion
*dest
,
496 union sockunion
*mask
)
498 if (dest
->sa
.sa_family
== AF_INET
)
500 struct prefix_ipv4
*p
;
502 p
= prefix_ipv4_new ();
504 p
->prefix
= dest
->sin
.sin_addr
;
505 p
->prefixlen
= ip_masklen (mask
->sin
.sin_addr
);
506 return (struct prefix
*) p
;
509 if (dest
->sa
.sa_family
== AF_INET6
)
511 struct prefix_ipv6
*p
;
513 p
= prefix_ipv6_new ();
514 p
->family
= AF_INET6
;
515 p
->prefixlen
= ip6_masklen (mask
->sin6
.sin6_addr
);
516 memcpy (&p
->prefix
, &dest
->sin6
.sin6_addr
, sizeof (struct in6_addr
));
517 return (struct prefix
*) p
;
519 #endif /* HAVE_IPV6 */
523 /* Utility function of convert between struct prefix <=> union sockunion */
525 sockunion2hostprefix (union sockunion
*su
)
527 if (su
->sa
.sa_family
== AF_INET
)
529 struct prefix_ipv4
*p
;
531 p
= prefix_ipv4_new ();
533 p
->prefix
= su
->sin
.sin_addr
;
534 p
->prefixlen
= IPV4_MAX_BITLEN
;
535 return (struct prefix
*) p
;
538 if (su
->sa
.sa_family
== AF_INET6
)
540 struct prefix_ipv6
*p
;
542 p
= prefix_ipv6_new ();
543 p
->family
= AF_INET6
;
544 p
->prefixlen
= IPV6_MAX_BITLEN
;
545 memcpy (&p
->prefix
, &su
->sin6
.sin6_addr
, sizeof (struct in6_addr
));
546 return (struct prefix
*) p
;
548 #endif /* HAVE_IPV6 */
553 prefix_blen (struct prefix
*p
)
558 return IPV4_MAX_BYTELEN
;
562 return IPV6_MAX_BYTELEN
;
564 #endif /* HAVE_IPV6 */
569 /* Generic function for conversion string to struct prefix. */
571 str2prefix (char *str
, struct prefix
*p
)
575 /* First we try to convert string to struct prefix_ipv4. */
576 ret
= str2prefix_ipv4 (str
, (struct prefix_ipv4
*) p
);
581 /* Next we try to convert string to struct prefix_ipv6. */
582 ret
= str2prefix_ipv6 (str
, (struct prefix_ipv6
*) p
);
585 #endif /* HAVE_IPV6 */
591 prefix2str (struct prefix
*p
, char *str
, int size
)
595 inet_ntop (p
->family
, &p
->u
.prefix
, buf
, BUFSIZ
);
596 snprintf (str
, size
, "%s/%d", buf
, p
->prefixlen
);
605 p
= XMALLOC (MTYPE_PREFIX
, sizeof *p
);
606 bzero (p
, sizeof (struct prefix
));
610 /* Free prefix structure. */
612 prefix_free (struct prefix
*p
)
614 XFREE (MTYPE_PREFIX
, p
);
617 /* Utility function. Check the string only contains digit
620 all_digit (char *str
)
622 for (; *str
!= '\0'; str
++)
623 if (!isdigit ((int) *str
))
628 /* Utility function to convert ipv4 prefixes to Classful prefixes */
629 void apply_classful_mask_ipv4 (struct prefix_ipv4
*p
)
632 u_int32_t destination
;
634 destination
= ntohl (p
->prefix
.s_addr
);
636 if (p
->prefixlen
== 32);
637 /* do nothing for host routes */
638 else if (IN_CLASSC (destination
))
643 else if (IN_CLASSB(destination
))
655 /* Utility function to convert ipv4 netmask to prefixes
656 ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16"
657 ex.) "1.0.0.0" NULL => "1.0.0.0/8" */
659 netmask_str2prefix_str (char *net_str
, char *mask_str
, char *prefix_str
)
661 struct in_addr network
;
664 u_int32_t destination
;
667 ret
= inet_aton (net_str
, &network
);
673 ret
= inet_aton (mask_str
, &mask
);
677 sprintf (masklen_str
, "%d", ip_masklen (mask
));
681 destination
= ntohl (network
.s_addr
);
683 if (network
.s_addr
== 0)
684 strcpy (masklen_str
, "0");
685 else if (IN_CLASSC (destination
))
686 strcpy (masklen_str
, "24");
687 else if (IN_CLASSB (destination
))
688 strcpy (masklen_str
, "16");
689 else if (IN_CLASSA (destination
))
690 strcpy (masklen_str
, "8");
695 strcpy (prefix_str
, net_str
);
696 strcat (prefix_str
, "/");
697 strcat (prefix_str
, masklen_str
);