util: Refactor isValidPrefix to reduce address family re-use

Change-Id: I13abd5b110709210b98b4ea74e3129c3ab42bd46
Signed-off-by: William A. Kennington III <wak@google.com>
diff --git a/src/util.cpp b/src/util.cpp
index 7935ba6..cef2966 100644
--- a/src/util.cpp
+++ b/src/util.cpp
@@ -138,6 +138,19 @@
 
 } // namespace internal
 
+constexpr auto familyVisit(auto&& visitor, int family)
+{
+    if (family == AF_INET)
+    {
+        return visitor.template operator()<AF_INET>();
+    }
+    else if (family == AF_INET6)
+    {
+        return visitor.template operator()<AF_INET6>();
+    }
+    throw std::invalid_argument("Invalid addr family");
+}
+
 std::string toMask(int addressFamily, uint8_t prefix)
 {
     if (addressFamily == AF_INET6)
@@ -234,27 +247,10 @@
     return inet_pton(addressFamily, address.c_str(), buf) > 0;
 }
 
-bool isValidPrefix(int addressFamily, uint8_t prefixLength)
+bool isValidPrefix(int family, uint8_t prefix)
 {
-    if (addressFamily == AF_INET)
-    {
-        if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
-            prefixLength > IPV4_MAX_PREFIX_LENGTH)
-        {
-            return false;
-        }
-    }
-
-    if (addressFamily == AF_INET6)
-    {
-        if (prefixLength < IPV4_MIN_PREFIX_LENGTH ||
-            prefixLength > IPV6_MAX_PREFIX_LENGTH)
-        {
-            return false;
-        }
-    }
-
-    return true;
+    return familyVisit(
+        [=]<int f>() noexcept { return isValidPrefix<f>(prefix); }, family);
 }
 
 InterfaceList getInterfaces()
diff --git a/src/util.hpp b/src/util.hpp
index dece269..f98a7d5 100644
--- a/src/util.hpp
+++ b/src/util.hpp
@@ -2,6 +2,7 @@
 #include "types.hpp"
 
 #include <netinet/ether.h>
+#include <netinet/in.h>
 #include <unistd.h>
 
 #include <cstring>
@@ -26,10 +27,6 @@
 using EthernetInterfaceIntf =
     sdbusplus::xyz::openbmc_project::Network::server::EthernetInterface;
 
-constexpr auto IPV4_MIN_PREFIX_LENGTH = 1;
-constexpr auto IPV4_MAX_PREFIX_LENGTH = 32;
-constexpr auto IPV6_MAX_PREFIX_LENGTH = 128;
-
 namespace mac_address
 {
 
@@ -75,6 +72,23 @@
 constexpr auto networkdService = "systemd-networkd.service";
 constexpr auto timeSynchdService = "systemd-timesyncd.service";
 
+template <int family>
+struct FamilyTraits
+{
+};
+
+template <>
+struct FamilyTraits<AF_INET>
+{
+    using addr = in_addr;
+};
+
+template <>
+struct FamilyTraits<AF_INET6>
+{
+    using addr = in6_addr;
+};
+
 /* @brief converts a sockaddr for the specified address family into
  *        a type_safe InAddrAny.
  * @param[in] addressFamily - The address family of the buf
@@ -98,11 +112,16 @@
 bool isValidIP(int addressFamily, stdplus::const_zstring address);
 
 /* @brief checks that the given prefix is valid or not.
- * @param[in] addressFamily - IP address family(AF_INET/AF_INET6).
+ * @param[in] family - IP address family(AF_INET/AF_INET6).
  * @param[in] prefix - prefix length.
  * @returns true if it is valid otherwise false.
  */
-bool isValidPrefix(int addressFamily, uint8_t prefixLength);
+template <int family>
+constexpr bool isValidPrefix(uint8_t prefix) noexcept
+{
+    return prefix <= sizeof(typename FamilyTraits<family>::addr) * 8;
+}
+bool isValidPrefix(int family, uint8_t prefixLength);
 
 /** @brief Get all the interfaces from the system.
  *  @returns list of interface names.
diff --git a/test/test_util.cpp b/test/test_util.cpp
index 677b3f6..5d05ffd 100644
--- a/test/test_util.cpp
+++ b/test/test_util.cpp
@@ -5,6 +5,7 @@
 
 #include <cstddef>
 #include <cstring>
+#include <stdexcept>
 #include <stdplus/raw.hpp>
 #include <string>
 #include <string_view>
@@ -108,23 +109,21 @@
 
 TEST_F(TestUtil, PrefixValidation)
 {
-    uint8_t prefixLength = 1;
-    EXPECT_EQ(true, isValidPrefix(AF_INET, prefixLength));
+    EXPECT_TRUE(isValidPrefix(AF_INET, 0));
+    EXPECT_TRUE(isValidPrefix(AF_INET, 1));
+    EXPECT_TRUE(isValidPrefix(AF_INET, 32));
+    EXPECT_FALSE(isValidPrefix(AF_INET, 33));
+    EXPECT_FALSE(isValidPrefix(AF_INET, 64));
 
-    prefixLength = 32;
-    EXPECT_EQ(true, isValidPrefix(AF_INET, prefixLength));
+    EXPECT_TRUE(isValidPrefix(AF_INET6, 0));
+    EXPECT_TRUE(isValidPrefix(AF_INET6, 1));
+    EXPECT_TRUE(isValidPrefix(AF_INET6, 53));
+    EXPECT_TRUE(isValidPrefix(AF_INET6, 64));
+    EXPECT_TRUE(isValidPrefix(AF_INET6, 128));
+    EXPECT_FALSE(isValidPrefix(AF_INET6, 129));
+    EXPECT_FALSE(isValidPrefix(AF_INET6, 177));
 
-    prefixLength = 0;
-    EXPECT_EQ(false, isValidPrefix(AF_INET, prefixLength));
-
-    prefixLength = 33;
-    EXPECT_EQ(false, isValidPrefix(AF_INET, prefixLength));
-
-    prefixLength = 33;
-    EXPECT_EQ(true, isValidPrefix(AF_INET6, prefixLength));
-
-    prefixLength = 65;
-    EXPECT_EQ(false, isValidPrefix(AF_INET, prefixLength));
+    EXPECT_THROW(isValidPrefix(AF_UNSPEC, 1), std::invalid_argument);
 }
 
 TEST_F(TestUtil, InterfaceToUbootEthAddr)