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
= XCALLOC (MTYPE_PREFIX_IPV4
, sizeof *p
);
192 /* Free prefix_ipv4 structure. */
194 prefix_ipv4_free (struct prefix_ipv4
*p
)
196 XFREE (MTYPE_PREFIX_IPV4
, p
);
199 /* When string format is invalid return 0. */
201 str2prefix_ipv4 (char *str
, struct prefix_ipv4
*p
)
208 /* Find slash inside string. */
209 pnt
= strchr (str
, '/');
211 /* String doesn't contail slash. */
214 /* Convert string to prefix. */
215 ret
= inet_aton (str
, &p
->prefix
);
219 /* If address doesn't contain slash we assume it host address. */
221 p
->prefixlen
= IPV4_MAX_BITLEN
;
227 cp
= XMALLOC (MTYPE_TMP
, (pnt
- str
) + 1);
228 strncpy (cp
, str
, pnt
- str
);
229 *(cp
+ (pnt
- str
)) = '\0';
230 ret
= inet_aton (cp
, &p
->prefix
);
231 XFREE (MTYPE_TMP
, cp
);
233 /* Get prefix length. */
234 plen
= (u_char
) atoi (++pnt
);
245 /* Convert masklen into IP address's netmask. */
247 masklen2ip (int masklen
, struct in_addr
*netmask
)
253 memset (netmask
, 0, sizeof (struct in_addr
));
254 pnt
= (unsigned char *) netmask
;
256 offset
= masklen
/ 8;
266 /* Convert IP address's netmask into integer. We assume netmask is
267 sequential one. Argument netmask should be network byte order. */
269 ip_masklen (struct in_addr netmask
)
277 pnt
= (u_char
*) &netmask
;
280 while ((*pnt
== 0xff) && pnt
< end
)
298 /* Apply mask to IPv4 prefix. */
300 apply_mask_ipv4 (struct prefix_ipv4
*p
)
306 index
= p
->prefixlen
/ 8;
310 pnt
= (u_char
*) &p
->prefix
;
311 offset
= p
->prefixlen
% 8;
313 pnt
[index
] &= maskbit
[offset
];
321 /* If prefix is 0.0.0.0/0 then return 1 else return 0. */
323 prefix_ipv4_any (struct prefix_ipv4
*p
)
325 return (p
->prefix
.s_addr
== 0 && p
->prefixlen
== 0);
330 /* Allocate a new ip version 6 route */
334 struct prefix_ipv6
*p
;
336 p
= XCALLOC (MTYPE_PREFIX_IPV6
, sizeof (struct prefix_ipv6
));
337 p
->family
= AF_INET6
;
341 /* Free prefix for IPv6. */
343 prefix_ipv6_free (struct prefix_ipv6
*p
)
345 XFREE (MTYPE_PREFIX_IPV6
, p
);
348 /* If given string is valid return pin6 else return NULL */
350 str2prefix_ipv6 (char *str
, struct prefix_ipv6
*p
)
356 pnt
= strchr (str
, '/');
358 /* If string doesn't contain `/' treat it as host route. */
361 ret
= inet_pton (AF_INET6
, str
, &p
->prefix
);
364 p
->prefixlen
= IPV6_MAX_BITLEN
;
370 cp
= XMALLOC (0, (pnt
- str
) + 1);
371 strncpy (cp
, str
, pnt
- str
);
372 *(cp
+ (pnt
- str
)) = '\0';
373 ret
= inet_pton (AF_INET6
, cp
, &p
->prefix
);
377 plen
= (u_char
) atoi (++pnt
);
382 p
->family
= AF_INET6
;
387 /* Convert struct in6_addr netmask into integer. */
389 ip6_masklen (struct in6_addr netmask
)
395 pnt
= (unsigned char *) & netmask
;
397 while ((*pnt
== 0xff) && len
< 128)
416 masklen2ip6 (int masklen
, struct in6_addr
*netmask
)
422 memset (netmask
, 0, sizeof (struct in6_addr
));
423 pnt
= (unsigned char *) netmask
;
425 offset
= masklen
/ 8;
436 apply_mask_ipv6 (struct prefix_ipv6
*p
)
442 index
= p
->prefixlen
/ 8;
446 pnt
= (u_char
*) &p
->prefix
;
447 offset
= p
->prefixlen
% 8;
449 pnt
[index
] &= maskbit
[offset
];
458 str2in6_addr (char *str
, struct in6_addr
*addr
)
463 /* %x must point to unsinged int */
464 for (i
= 0; i
< 16; i
++)
466 sscanf (str
+ (i
* 2), "%02x", &x
);
467 addr
->s6_addr
[i
] = x
& 0xff;
470 #endif /* HAVE_IPV6 */
473 apply_mask (struct prefix
*p
)
478 apply_mask_ipv4 ((struct prefix_ipv4
*)p
);
482 apply_mask_ipv6 ((struct prefix_ipv6
*)p
);
484 #endif /* HAVE_IPV6 */
491 /* Utility function of convert between struct prefix <=> union sockunion */
493 sockunion2prefix (union sockunion
*dest
,
494 union sockunion
*mask
)
496 if (dest
->sa
.sa_family
== AF_INET
)
498 struct prefix_ipv4
*p
;
500 p
= prefix_ipv4_new ();
502 p
->prefix
= dest
->sin
.sin_addr
;
503 p
->prefixlen
= ip_masklen (mask
->sin
.sin_addr
);
504 return (struct prefix
*) p
;
507 if (dest
->sa
.sa_family
== AF_INET6
)
509 struct prefix_ipv6
*p
;
511 p
= prefix_ipv6_new ();
512 p
->family
= AF_INET6
;
513 p
->prefixlen
= ip6_masklen (mask
->sin6
.sin6_addr
);
514 memcpy (&p
->prefix
, &dest
->sin6
.sin6_addr
, sizeof (struct in6_addr
));
515 return (struct prefix
*) p
;
517 #endif /* HAVE_IPV6 */
521 /* Utility function of convert between struct prefix <=> union sockunion */
523 sockunion2hostprefix (union sockunion
*su
)
525 if (su
->sa
.sa_family
== AF_INET
)
527 struct prefix_ipv4
*p
;
529 p
= prefix_ipv4_new ();
531 p
->prefix
= su
->sin
.sin_addr
;
532 p
->prefixlen
= IPV4_MAX_BITLEN
;
533 return (struct prefix
*) p
;
536 if (su
->sa
.sa_family
== AF_INET6
)
538 struct prefix_ipv6
*p
;
540 p
= prefix_ipv6_new ();
541 p
->family
= AF_INET6
;
542 p
->prefixlen
= IPV6_MAX_BITLEN
;
543 memcpy (&p
->prefix
, &su
->sin6
.sin6_addr
, sizeof (struct in6_addr
));
544 return (struct prefix
*) p
;
546 #endif /* HAVE_IPV6 */
551 prefix_blen (struct prefix
*p
)
556 return IPV4_MAX_BYTELEN
;
560 return IPV6_MAX_BYTELEN
;
562 #endif /* HAVE_IPV6 */
567 /* Generic function for conversion string to struct prefix. */
569 str2prefix (char *str
, struct prefix
*p
)
573 /* First we try to convert string to struct prefix_ipv4. */
574 ret
= str2prefix_ipv4 (str
, (struct prefix_ipv4
*) p
);
579 /* Next we try to convert string to struct prefix_ipv6. */
580 ret
= str2prefix_ipv6 (str
, (struct prefix_ipv6
*) p
);
583 #endif /* HAVE_IPV6 */
589 prefix2str (struct prefix
*p
, char *str
, int size
)
593 inet_ntop (p
->family
, &p
->u
.prefix
, buf
, BUFSIZ
);
594 snprintf (str
, size
, "%s/%d", buf
, p
->prefixlen
);
603 p
= XCALLOC (MTYPE_PREFIX
, sizeof *p
);
607 /* Free prefix structure. */
609 prefix_free (struct prefix
*p
)
611 XFREE (MTYPE_PREFIX
, p
);
614 /* Utility function. Check the string only contains digit
617 all_digit (char *str
)
619 for (; *str
!= '\0'; str
++)
620 if (!isdigit ((int) *str
))
625 /* Utility function to convert ipv4 prefixes to Classful prefixes */
626 void apply_classful_mask_ipv4 (struct prefix_ipv4
*p
)
629 u_int32_t destination
;
631 destination
= ntohl (p
->prefix
.s_addr
);
633 if (p
->prefixlen
== 32);
634 /* do nothing for host routes */
635 else if (IN_CLASSC (destination
))
640 else if (IN_CLASSB(destination
))
652 /* Utility function to convert ipv4 netmask to prefixes
653 ex.) "1.1.0.0" "255.255.0.0" => "1.1.0.0/16"
654 ex.) "1.0.0.0" NULL => "1.0.0.0/8" */
656 netmask_str2prefix_str (char *net_str
, char *mask_str
, char *prefix_str
)
658 struct in_addr network
;
661 u_int32_t destination
;
664 ret
= inet_aton (net_str
, &network
);
670 ret
= inet_aton (mask_str
, &mask
);
674 prefixlen
= ip_masklen (mask
);
678 destination
= ntohl (network
.s_addr
);
680 if (network
.s_addr
== 0)
682 else if (IN_CLASSC (destination
))
684 else if (IN_CLASSB (destination
))
686 else if (IN_CLASSA (destination
))
692 sprintf (prefix_str
, "%s/%d", net_str
, prefixlen
);