]> git.puffer.fish Git - mirror/frr.git/commitdiff
lib: prefix2sockunion, prefix_common_bits helper functions
authorDavid Lamparter <equinox@diac24.net>
Tue, 2 Feb 2010 19:16:35 +0000 (20:16 +0100)
committerDenis Ovsienko <infrastation@yandex.ru>
Mon, 21 Nov 2011 14:23:10 +0000 (18:23 +0400)
prefix2sockunion converts a struct prefix* to a union sockunion *;
prefix_common_bits counts the number of common bits in the prefix's
address part.

lib/prefix.c
lib/prefix.h

index 9633a89473ba5a896473544154d22625b7f82fd8..4be3ba20151ddd94b01c4d9007047d2beeb1b1ad 100644 (file)
@@ -253,6 +253,46 @@ prefix_cmp (const struct prefix *p1, const struct prefix *p2)
   return 0;
 }
 
+/*
+ * Count the number of common bits in 2 prefixes. The prefix length is
+ * ignored for this function; the whole prefix is compared. If the prefix
+ * address families don't match, return -1; otherwise the return value is
+ * in range 0 ... maximum prefix length for the address family.
+ */
+int
+prefix_common_bits (const struct prefix *p1, const struct prefix *p2)
+{
+  int pos, bit;
+  int length = 0;
+  u_char xor;
+
+  /* Set both prefix's head pointer. */
+  const u_char *pp1 = (const u_char *)&p1->u.prefix;
+  const u_char *pp2 = (const u_char *)&p2->u.prefix;
+
+  if (p1->family == AF_INET)
+    length = IPV4_MAX_BYTELEN;
+#ifdef HAVE_IPV6
+  if (p1->family == AF_INET6)
+    length = IPV6_MAX_BYTELEN;
+#endif
+  if (p1->family != p2->family || !length)
+    return -1;
+
+  for (pos = 0; pos < length; pos++)
+    if (pp1[pos] != pp2[pos])
+      break;
+  if (pos == length)
+    return pos * 8;
+
+  xor = pp1[pos] ^ pp2[pos];
+  for (bit = 0; bit < 8; bit++)
+    if (xor & (1 << (7 - bit)))
+      break;
+
+  return pos * 8 + bit;
+}
+
 /* Return prefix family type string. */
 const char *
 prefix_family_str (const struct prefix *p)
@@ -629,6 +669,20 @@ sockunion2hostprefix (const union sockunion *su)
   return NULL;
 }
 
+void
+prefix2sockunion (const struct prefix *p, union sockunion *su)
+{
+  memset (su, 0, sizeof (*su));
+
+  su->sa.sa_family = p->family;
+  if (p->family == AF_INET)
+    su->sin.sin_addr = p->u.prefix4;
+#ifdef HAVE_IPV6
+  if (p->family == AF_INET6)
+    memcpy (&su->sin6.sin6_addr, &p->u.prefix6, sizeof (struct in6_addr));
+#endif /* HAVE_IPV6 */
+}
+
 int
 prefix_blen (const struct prefix *p)
 {
index 423346494e2dbd8cf7ea3361d5d923aebd3e12a2..675f94d49014f50fa0810dd9330f4285cdbecbd2 100644 (file)
@@ -157,12 +157,14 @@ extern int prefix2str (const struct prefix *, char *, int);
 extern int prefix_match (const struct prefix *, const struct prefix *);
 extern int prefix_same (const struct prefix *, const struct prefix *);
 extern int prefix_cmp (const struct prefix *, const struct prefix *);
+extern int prefix_common_bits (const struct prefix *, const struct prefix *);
 extern void prefix_copy (struct prefix *dest, const struct prefix *src);
 extern void apply_mask (struct prefix *);
 
 extern struct prefix *sockunion2prefix (const union sockunion *dest,
                                         const union sockunion *mask);
 extern struct prefix *sockunion2hostprefix (const union sockunion *);
+extern void prefix2sockunion (const struct prefix *, union sockunion *);
 
 extern struct prefix_ipv4 *prefix_ipv4_new (void);
 extern void prefix_ipv4_free (struct prefix_ipv4 *);