From bcc964426be65236f383284d3d838ec325178a53 Mon Sep 17 00:00:00 2001 From: Yenda Li Date: Tue, 12 Nov 2024 10:06:57 -0800 Subject: [PATCH] Add ipprefix cast operators for ipaddr [2/n] (#11481) Summary: Support casting ipprefix -> ipaddress, and ipaddress -> ipprefix. We just need one new helper function, tryIpPrefixLengthFromIPAddressType, which takes in int128_t, gets the ippaddress, and then we check if the ippaddress is ipv4 or ipv6 mapped. We return 32 for ipv4 and 128 for ipv6 mapped. Also applies suggestion from https://github.com/facebookincubator/velox/pull/11309/files Differential Revision: D65641994 --- velox/docs/functions/presto/conversion.rst | 213 ++++++++++++++---- .../prestosql/tests/IPAddressCastTest.cpp | 25 ++ .../prestosql/tests/IPPrefixCastTest.cpp | 76 +++++++ .../prestosql/types/IPAddressType.cpp | 56 +++++ .../prestosql/types/IPPrefixType.cpp | 48 +++- .../functions/prestosql/types/IPPrefixType.h | 84 ++----- 6 files changed, 384 insertions(+), 118 deletions(-) diff --git a/velox/docs/functions/presto/conversion.rst b/velox/docs/functions/presto/conversion.rst index b24117ae3068a..a2d96843b3254 100644 --- a/velox/docs/functions/presto/conversion.rst +++ b/velox/docs/functions/presto/conversion.rst @@ -30,7 +30,7 @@ are supported if the conversion of their element types are supported. In additio supported conversions to/from JSON are listed in :doc:`json`. .. list-table:: - :widths: 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 + :widths: 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 25 :header-rows: 1 * - @@ -49,6 +49,7 @@ supported conversions to/from JSON are listed in :doc:`json`. - interval day to second - decimal - ipaddress + - ipprefix * - tinyint - Y - Y @@ -58,13 +59,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - smallint - Y - Y @@ -74,13 +76,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - integer - Y - Y @@ -90,13 +93,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - bigint - Y - Y @@ -106,13 +110,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - boolean - Y - Y @@ -122,13 +127,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - real - Y - Y @@ -138,13 +144,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - double - Y - Y @@ -154,13 +161,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - - + - + - * - varchar - Y - Y @@ -170,29 +178,31 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - Y - Y - Y - - Y - Y + - Y * - varbinary - - - - - - - - - - - - - - - - - - - - - - - - - - - - + - + - + - + - + - + - + - + - + - + - + - + - + - + - - Y + - * - timestamp - - @@ -202,13 +212,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - - - Y - - + - - Y - Y - Y - - - - + - + - * - timestamp with time zone - - @@ -218,13 +229,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - - - Y - - + - - Y - - Y - - - + - * - date - - @@ -234,13 +246,14 @@ supported conversions to/from JSON are listed in :doc:`json`. - - - Y - - + - - Y - Y - - - - + - * - interval day to second - - @@ -250,7 +263,8 @@ supported conversions to/from JSON are listed in :doc:`json`. - - - Y - - + - + - - - - @@ -266,30 +280,48 @@ supported conversions to/from JSON are listed in :doc:`json`. - Y - Y - Y - - + - - - - - - Y - + - * - ipaddress - - - - - - - - - - - - - - + - + - + - + - + - + - + - - Y - Y - - - - - - - - - + - + - + - Y + * - ipprefix + - + - + - + - + - + - + - + - Y + - + - + - + - + - + - + - Y + - Y Cast to Integral Types ---------------------- @@ -689,6 +721,33 @@ IPV4 mapped IPV6: SELECT cast(ipaddress '::ffff:ffff:ffff' as varchar); -- '255.255.255.255' +From IPPREFIX +^^^^^^^^^^^^^ + +Casting from IPPREFIX to VARCHAR returns a string formatted as *x.x.x.x/* for IPv4 formatted IPv6 addresses. + +For all other IPv6 addresses it will be formatted in compressed alternate form IPv6 defined in `RFC 4291#section-2.2 `_ +followed by */*. [`RFC 4291#section-2.3 `_] + +IPv4: + +:: + + SELECT cast(ipprefix '1.2.0.0/16' as varchar); -- '1.2.0.0/16' + +IPv6: + +:: + + SELECT cast(ipprefix '2001:db8::ff00:42:8329/128' as varchar); -- '2001:db8::ff00:42:8329/128' + SELECT cast(ipprefix '0:0:0:0:0:0:13.1.68.3/32' as varchar); -- '::/32' + +IPv4 mapped IPv6: + +:: + + SELECT cast(ipaddress '::ffff:ffff:0000/16' as varchar); -- '255.255.0.0/16' + Cast to VARBINARY ----------------- @@ -1036,6 +1095,8 @@ Invalid example Cast to IPADDRESS ----------------- +.. _ipaddress-from-varchar: + From VARCHAR ^^^^^^^^^^^^ @@ -1128,6 +1189,66 @@ Invalid examples: SELECT cast(from_hex('f000001100') as ipaddress); -- Invalid IP address binary length: 5 +From IPPREFIX +^^^^^^^^^^^^^ + +Returns the canonical(lowest) IPADDRESS in the subnet range. + +Examples: + +:: + + SELECT cast(ipprefix '1.2.3.4/24' as ipaddress) -- ipaddress '1.2.3.0' + SELECT cast(ipprefix '2001:db8::ff00:42:8329/64' as ipaddress) -- ipaddress '2001:db8::' + +Cast to IPPREFIX +---------------- + +From VARCHAR +^^^^^^^^^^^^ + +The IPPREFIX string must be in the form of */* as defined in `RFC 4291#section-2.3 `_. +The IPADDRESS portion of the IPPREFIX follows the same rules as casting +`IPADDRESS from VARCHAR <#ipaddress-from-varchar>`_. + +The prefix portion must be <= 32 if the IP is an IPv4 address or <= 128 for an IPv6 address. +As with IPADDRESS, any IPv6 address in the form of an IPv4 mapped IPv6 address will be +interpreted as an IPv4 address. Only the canonical(smallest) IP address will be stored +in the IPPREFIX. + +Examples: + +Valid examples: + +:: + + SELECT cast('2001:0db8:0000:0000:0000:ff00:0042:8329/32' as ipprefix); -- ipprefix '2001:0db8::/32' + SELECT cast('1.2.3.4/24' as ipprefix); -- ipprefix '1.2.3.0/24' + SELECT cast('::ffff:ffff:ffff/16' as ipprefix); -- ipprefix '255.255.0.0/16' + +Invalid examples: + +:: + + SELECT cast('2001:db8::1::1/1' as ipprefix); -- Cannot cast value to IPPREFIX: 2001:db8::1::1/1 + SELECT cast('2001:0db8:0000:0000:0000:ff00:0042:8329/129' as ipprefix); -- Cannot cast value to IPPREFIX: 2001:0db8:0000:0000:0000:ff00:0042:8329/129 + SELECT cast('2001:0db8:0000:0000:0000:ff00:0042:8329/-1' as ipprefix); -- Cannot cast value to IPPREFIX: 2001:0db8:0000:0000:0000:ff00:0042:8329/-1 + SELECT cast('255.2.3.4/33' as ipprefix); -- Cannot cast value to IPPREFIX: 255.2.3.4/33 + SELECT cast('::ffff:ffff:ffff/33' as ipprefix); -- Cannot cast value to IPPREFIX: ::ffff:ffff:ffff/33 + +From IPADDRESS +^^^^^^^^^^^^^^ + +Returns an IPPREFIX where the prefix length is the length of the entire IP address. +Prefix length for IPv4 is 32 and for IPv6 it is 128. + +Examples: + +:: + + SELECT cast(ipaddress '1.2.3.4' as ipprefix) -- ipprefix '1.2.3.4/32' + SELECT cast(ipaddress '2001:db8::ff00:42:8329' as ipprefix) -- ipprefix '2001:db8::ff00:42:8329/128' + Miscellaneous ------------- diff --git a/velox/functions/prestosql/tests/IPAddressCastTest.cpp b/velox/functions/prestosql/tests/IPAddressCastTest.cpp index a13ec9114e94a..d211f031a3cfe 100644 --- a/velox/functions/prestosql/tests/IPAddressCastTest.cpp +++ b/velox/functions/prestosql/tests/IPAddressCastTest.cpp @@ -43,6 +43,13 @@ class IPAddressCastTest : public functions::test::FunctionBaseTest { input); return result; } + + auto castToIPPrefixAndBackToIpVarchar( + const std::optional& input) { + return evaluateOnce( + "cast(cast(cast(cast(cast(cast(c0 as ipaddress) as ipprefix) as varchar) as ipprefix) as ipaddress) as varchar)", + input); + } }; int128_t stringToInt128(const std::string& value) { @@ -53,6 +60,24 @@ int128_t stringToInt128(const std::string& value) { return res; } +TEST_F(IPAddressCastTest, castToIPPrefix) { + EXPECT_EQ(castToIPPrefixAndBackToIpVarchar("1.2.3.4"), "1.2.3.4"); + EXPECT_EQ(castToIPPrefixAndBackToIpVarchar("::ffff:1.2.3.4"), "1.2.3.4"); + EXPECT_EQ(castToIPPrefixAndBackToIpVarchar("::ffff:102:304"), "1.2.3.4"); + EXPECT_EQ(castToIPPrefixAndBackToIpVarchar("192.168.0.0"), "192.168.0.0"); + EXPECT_EQ( + castToIPPrefixAndBackToIpVarchar( + "2001:0db8:0000:0000:0000:ff00:0042:8329"), + "2001:db8::ff00:42:8329"); + EXPECT_EQ( + castToIPPrefixAndBackToIpVarchar("2001:db8:0:0:1:0:0:1"), + "2001:db8::1:0:0:1"); + EXPECT_EQ(castToIPPrefixAndBackToIpVarchar("::1"), "::1"); + EXPECT_EQ( + castToIPPrefixAndBackToIpVarchar("2001:db8::ff00:42:8329"), + "2001:db8::ff00:42:8329"); +} + TEST_F(IPAddressCastTest, castToVarchar) { EXPECT_EQ(castToVarchar("::ffff:1.2.3.4"), "1.2.3.4"); EXPECT_EQ(castToVarchar("0:0:0:0:0:0:13.1.68.3"), "::13.1.68.3"); diff --git a/velox/functions/prestosql/tests/IPPrefixCastTest.cpp b/velox/functions/prestosql/tests/IPPrefixCastTest.cpp index c8c77f40ec528..9fcd711b3d2b6 100644 --- a/velox/functions/prestosql/tests/IPPrefixCastTest.cpp +++ b/velox/functions/prestosql/tests/IPPrefixCastTest.cpp @@ -14,6 +14,7 @@ * limitations under the License. */ +#include "velox/common/base/tests/GTestUtils.h" #include "velox/functions/prestosql/tests/utils/FunctionBaseTest.h" namespace facebook::velox::functions::prestosql { @@ -26,8 +27,83 @@ class IPPrefixTypeTest : public functions::test::FunctionBaseTest { "cast(cast(c0 as ipprefix) as varchar)", input); return result; } + + std::optional castToIpAddress( + const std::optional& input) { + return evaluateOnce( + "cast(cast(cast(c0 as ipprefix) as ipaddress) as varchar)", input); + } + + std::optional castFromIPAddress( + const std::optional& input) { + return evaluateOnce( + "cast(cast(cast(c0 as ipaddress) as ipprefix) as varchar)", input); + } }; +TEST_F(IPPrefixTypeTest, invalidIPPrefix) { + VELOX_ASSERT_THROW( + castToVarchar("facebook.com/32"), + "Cannot cast value to IPPREFIX: facebook.com"); + VELOX_ASSERT_THROW( + castToVarchar("localhost/32"), + "Cannot cast value to IPPREFIX: localhost"); + VELOX_ASSERT_THROW( + castToVarchar("2001:db8::1::1/128"), + "Cannot cast value to IPPREFIX: 2001:db8::1::1"); + VELOX_ASSERT_THROW( + castToVarchar("2001:zxy::1::1/128"), + "Cannot cast value to IPPREFIX: 2001:zxy::1::1"); + VELOX_ASSERT_THROW( + castToVarchar("789.1.1.1/32"), + "Cannot cast value to IPPREFIX: 789.1.1.1"); + VELOX_ASSERT_THROW( + castToVarchar("192.1.1.1"), "Cannot cast value to IPPREFIX: 192.1.1.1"); + VELOX_ASSERT_THROW( + castToVarchar("192.1.1.1/128"), + "Cannot cast value to IPPREFIX: 192.1.1.1/128"); + VELOX_ASSERT_THROW( + castToVarchar("192.1.1.1/-1"), + "Cannot cast value to IPPREFIX: 192.1.1.1/-1"); + VELOX_ASSERT_THROW( + castToVarchar("::ffff:ffff:ffff/33"), + "Cannot cast value to IPPREFIX: ::ffff:ffff:ffff/33"); + VELOX_ASSERT_THROW( + castToVarchar("::ffff:ffff:ffff/-1"), + "Cannot cast value to IPPREFIX: ::ffff:ffff:ffff/-1"); + VELOX_ASSERT_THROW( + castToVarchar("::/129"), "Cannot cast value to IPPREFIX: ::/129"); + VELOX_ASSERT_THROW( + castToVarchar("::/-1"), "Cannot cast value to IPPREFIX: ::/-1"); +} + +TEST_F(IPPrefixTypeTest, castFromIpAddress) { + EXPECT_EQ(castFromIPAddress(std::nullopt), std::nullopt); + EXPECT_EQ(castFromIPAddress("1.2.3.4"), "1.2.3.4/32"); + EXPECT_EQ(castFromIPAddress("::ffff:1.2.3.4"), "1.2.3.4/32"); + EXPECT_EQ(castFromIPAddress("::ffff:102:304"), "1.2.3.4/32"); + EXPECT_EQ(castFromIPAddress("192.168.0.0"), "192.168.0.0/32"); + EXPECT_EQ( + castFromIPAddress("2001:0db8:0000:0000:0000:ff00:0042:8329"), + "2001:db8::ff00:42:8329/128"); + EXPECT_EQ(castFromIPAddress("2001:db8:0:0:1:0:0:1"), "2001:db8::1:0:0:1/128"); + EXPECT_EQ(castFromIPAddress("::1"), "::1/128"); + EXPECT_EQ( + castFromIPAddress("2001:db8::ff00:42:8329"), + "2001:db8::ff00:42:8329/128"); + EXPECT_EQ(castFromIPAddress("2001:db8::"), "2001:db8::/128"); +} + +TEST_F(IPPrefixTypeTest, castToIpAddress) { + EXPECT_EQ(castToIpAddress(std::nullopt), std::nullopt); + EXPECT_EQ(castToIpAddress("1.2.3.4/32"), "1.2.3.4"); + EXPECT_EQ(castToIpAddress("1.2.3.4/24"), "1.2.3.0"); + EXPECT_EQ(castToIpAddress("::1/128"), "::1"); + EXPECT_EQ( + castToIpAddress("2001:db8::ff00:42:8329/128"), "2001:db8::ff00:42:8329"); + EXPECT_EQ(castToIpAddress("2001:db8::ff00:42:8329/64"), "2001:db8::"); +} + TEST_F(IPPrefixTypeTest, castToVarchar) { EXPECT_EQ(castToVarchar("::ffff:1.2.3.4/24"), "1.2.3.0/24"); EXPECT_EQ(castToVarchar("192.168.0.0/24"), "192.168.0.0/24"); diff --git a/velox/functions/prestosql/types/IPAddressType.cpp b/velox/functions/prestosql/types/IPAddressType.cpp index d9569c01f7a97..d98b4c6174a21 100644 --- a/velox/functions/prestosql/types/IPAddressType.cpp +++ b/velox/functions/prestosql/types/IPAddressType.cpp @@ -16,6 +16,8 @@ #include "velox/functions/prestosql/types/IPAddressType.h" #include "velox/expression/CastExpr.h" +#include "velox/expression/VectorWriters.h" +#include "velox/functions/prestosql/types/IPPrefixType.h" namespace facebook::velox { @@ -28,6 +30,11 @@ class IPAddressCastOperator : public exec::CastOperator { case TypeKind::VARBINARY: case TypeKind::VARCHAR: return true; + case TypeKind::ROW: + if (isIPPrefixType(other)) { + return true; + } + [[fallthrough]]; default: return false; } @@ -38,6 +45,11 @@ class IPAddressCastOperator : public exec::CastOperator { case TypeKind::VARBINARY: case TypeKind::VARCHAR: return true; + case TypeKind::ROW: + if (isIPPrefixType(other)) { + return true; + } + [[fallthrough]]; default: return false; } @@ -55,6 +67,9 @@ class IPAddressCastOperator : public exec::CastOperator { castFromString(input, context, rows, *result); } else if (input.typeKind() == TypeKind::VARBINARY) { castFromVarbinary(input, context, rows, *result); + } else if ( + input.typeKind() == TypeKind::ROW && isIPPrefixType(input.type())) { + castFromIPPrefix(input, context, rows, *result); } else { VELOX_UNSUPPORTED( "Cast from {} to IPAddress not supported", resultType->toString()); @@ -73,6 +88,9 @@ class IPAddressCastOperator : public exec::CastOperator { castToString(input, context, rows, *result); } else if (resultType->kind() == TypeKind::VARBINARY) { castToVarbinary(input, context, rows, *result); + } else if ( + resultType->kind() == TypeKind::ROW && isIPPrefixType(resultType)) { + castToIPPrefix(input, context, rows, *result); } else { VELOX_UNSUPPORTED( "Cast from IPAddress to {} not supported", resultType->toString()); @@ -155,6 +173,44 @@ class IPAddressCastOperator : public exec::CastOperator { }); } + static void castToIPPrefix( + const BaseVector& input, + exec::EvalCtx& context, + const SelectivityVector& rows, + BaseVector& result) { + auto* rowVectorResult = result.as(); + const auto* ipaddresses = input.as>(); + + context.applyToSelectedNoThrow(rows, [&](auto row) { + const auto ipAddrVal = ipaddresses->valueAt(row); + const auto tryPrefixLength = + ipaddress::tryIpPrefixLengthFromIPAddressType(ipAddrVal); + if (FOLLY_UNLIKELY(tryPrefixLength.hasError())) { + context.setStatus(row, std::move(tryPrefixLength).error()); + return; + } + + rowVectorResult->childAt(0)->as>()->set( + row, ipAddrVal); + rowVectorResult->childAt(1)->as>()->set( + row, tryPrefixLength.value()); + }); + } + + static void castFromIPPrefix( + const BaseVector& input, + exec::EvalCtx& context, + const SelectivityVector& rows, + BaseVector& result) { + auto* flatResult = result.as>(); + const auto* ipprefix = input.as(); + const auto* ipaddr = + ipprefix->childAt(ipaddress::kIpRowIndex)->as>(); + + context.applyToSelectedNoThrow( + rows, [&](auto row) { flatResult->set(row, ipaddr->valueAt(row)); }); + } + static void castFromVarbinary( const BaseVector& input, exec::EvalCtx& context, diff --git a/velox/functions/prestosql/types/IPPrefixType.cpp b/velox/functions/prestosql/types/IPPrefixType.cpp index b835876df2322..9bfb41ccb7b6f 100644 --- a/velox/functions/prestosql/types/IPPrefixType.cpp +++ b/velox/functions/prestosql/types/IPPrefixType.cpp @@ -16,7 +16,6 @@ #include #include "velox/expression/CastExpr.h" -#include "velox/expression/VectorWriters.h" #include "velox/functions/prestosql/types/IPPrefixType.h" namespace facebook::velox { @@ -29,6 +28,8 @@ class IPPrefixCastOperator : public exec::CastOperator { switch (other->kind()) { case TypeKind::VARCHAR: return true; + case TypeKind::HUGEINT: + return isIPAddressType(other); default: return false; } @@ -38,6 +39,8 @@ class IPPrefixCastOperator : public exec::CastOperator { switch (other->kind()) { case TypeKind::VARCHAR: return true; + case TypeKind::HUGEINT: + return isIPAddressType(other); default: return false; } @@ -53,6 +56,12 @@ class IPPrefixCastOperator : public exec::CastOperator { switch (input.typeKind()) { case TypeKind::VARCHAR: return castFromString(input, context, rows, *result); + case TypeKind::HUGEINT: { + if (isIPAddressType(input.type())) { + return castFromIpAddress(input, context, rows, *result); + } + [[fallthrough]]; + } default: VELOX_NYI( "Cast from {} to IPPrefix not yet supported", @@ -85,7 +94,6 @@ class IPPrefixCastOperator : public exec::CastOperator { BaseVector& result) { auto* flatResult = result.as>(); auto rowVector = input.as(); - auto rowType = rowVector->type(); const auto* ipaddr = rowVector->childAt(ipaddress::kIpRowIndex) ->as>(); const auto* prefix = rowVector->childAt(ipaddress::kIpPrefixRowIndex) @@ -120,6 +128,30 @@ class IPPrefixCastOperator : public exec::CastOperator { }); } + static void castFromIpAddress( + const BaseVector& input, + exec::EvalCtx& context, + const SelectivityVector& rows, + BaseVector& result) { + auto* rowVectorResult = result.as(); + const auto* ipAddrVector = input.as>(); + + context.applyToSelectedNoThrow(rows, [&](auto row) { + auto intIpAddr = ipAddrVector->valueAt(row); + const auto tryPrefixLength = + ipaddress::tryIpPrefixLengthFromIPAddressType(intIpAddr); + if (FOLLY_UNLIKELY(tryPrefixLength.hasError())) { + context.setStatus(row, std::move(tryPrefixLength.error())); + return; + } + + rowVectorResult->childAt(0)->as>()->set( + row, intIpAddr); + rowVectorResult->childAt(1)->as>()->set( + row, tryPrefixLength.value()); + }); + } + static void castFromString( const BaseVector& input, exec::EvalCtx& context, @@ -133,16 +165,14 @@ class IPPrefixCastOperator : public exec::CastOperator { auto tryIpPrefix = ipaddress::tryParseIpPrefixString(ipAddressStringView); if (tryIpPrefix.hasError()) { context.setStatus(row, std::move(tryIpPrefix.error())); + return; } const auto& ipPrefix = tryIpPrefix.value(); - auto writer = exec::VectorWriter>(); - writer.init(*rowVectorResult); - writer.setOffset(row); - auto& rowWriter = writer.current(); - rowWriter.get_writer_at<0>() = ipPrefix.first; - rowWriter.get_writer_at<1>() = ipPrefix.second; - writer.commit(); + rowVectorResult->childAt(0)->as>()->set( + row, ipPrefix.first); + rowVectorResult->childAt(1)->as>()->set( + row, ipPrefix.second); }); } }; diff --git a/velox/functions/prestosql/types/IPPrefixType.h b/velox/functions/prestosql/types/IPPrefixType.h index bb387ef6f496d..6d7a2fb1d8917 100644 --- a/velox/functions/prestosql/types/IPPrefixType.h +++ b/velox/functions/prestosql/types/IPPrefixType.h @@ -32,62 +32,22 @@ constexpr int kIPPrefixBytes = 17; constexpr auto kIpRowIndex = "ip"; constexpr auto kIpPrefixRowIndex = "prefix"; -namespace { -auto splitIpSlashCidr(folly::StringPiece ipSlashCidr) { - folly::small_vector vec; - folly::split('/', ipSlashCidr, vec); - return vec; -} - -Status handleFailedToCreateNetworkError( - folly::StringPiece ipaddress, - folly::CIDRNetworkError error) { - if (threadSkipErrorDetails()) { - return Status::UserError(); +inline folly::Expected tryIpPrefixLengthFromIPAddressType( + const int128_t& intIpAddr) { + folly::ByteArray16 addrBytes = {0}; + memcpy(&addrBytes, &intIpAddr, sizeof(intIpAddr)); + std::reverse(addrBytes.begin(), addrBytes.end()); + auto tryV6Addr = folly::IPAddressV6::tryFromBinary(addrBytes); + if (tryV6Addr.hasError()) { + return folly::makeUnexpected( + threadSkipErrorDetails() + ? Status::UserError() + : Status::UserError("Received invalid ip address")); } - switch (error) { - case folly::CIDRNetworkError::INVALID_DEFAULT_CIDR: { - return Status::UserError( - "defaultCidr must be <= std::numeric_limits::max()"); - } - case folly::CIDRNetworkError::INVALID_IP_SLASH_CIDR: { - return Status::UserError( - "Invalid IP address string received. Received string:{} of length:{}", - ipaddress, - ipaddress.size()); - } - case folly::CIDRNetworkError::INVALID_IP: { - const auto vec = splitIpSlashCidr(ipaddress); - return Status::UserError( - "Invalid IP address '{}'", vec.size() > 0 ? vec.at(0) : ""); - } - case folly::CIDRNetworkError::INVALID_CIDR: { - auto const vec = splitIpSlashCidr(ipaddress); - return Status::UserError( - "Mask value '{}' not a valid mask", vec.size() > 1 ? vec.at(1) : ""); - } - case folly::CIDRNetworkError::CIDR_MISMATCH: { - const auto vec = splitIpSlashCidr(ipaddress); - if (!vec.empty()) { - const auto subnet = folly::IPAddress::tryFromString(vec.at(0)).value(); - return Status::UserError( - "CIDR value '{}' is > network bit count '{}'", - vec.size() == 2 ? vec.at(1) - : folly::to( - subnet.isV4() ? ipaddress::kIPV4Bits - : ipaddress::kIPV6Bits), - subnet.bitCount()); - } - return Status::UserError( - "Invalid IP address of size:{} received", ipaddress.size()); - } - default: - return Status::UserError( - "Unknown parsing error when parsing IP address: {} ", ipaddress); - } + return tryV6Addr.value().isIPv4Mapped() ? ipaddress::kIPV4Bits + : ipaddress::kIPV6Bits; } -} // namespace inline folly::Expected, Status> tryParseIpPrefixString(folly::StringPiece ipprefixString) { @@ -97,15 +57,17 @@ tryParseIpPrefixString(folly::StringPiece ipprefixString) { threadSkipErrorDetails() ? Status::UserError() : Status::UserError( - "Invalid CIDR IP address specified. Expected IP/PREFIX format, got: {}", - ipprefixString)); + "Cannot cast value to IPPREFIX: {}", ipprefixString)); } auto tryCdirNetwork = folly::IPAddress::tryCreateNetwork( ipprefixString, /*defaultCidr*/ -1, /*applyMask*/ false); if (tryCdirNetwork.hasError()) { - return folly::makeUnexpected(handleFailedToCreateNetworkError( - ipprefixString, std::move(tryCdirNetwork.error()))); + return folly::makeUnexpected( + threadSkipErrorDetails() + ? Status::UserError() + : Status::UserError( + "Cannot cast value to IPPREFIX: {}", ipprefixString)); } folly::ByteArray16 addrBytes; @@ -117,9 +79,7 @@ tryParseIpPrefixString(folly::StringPiece ipprefixString) { threadSkipErrorDetails() ? Status::UserError() : Status::UserError( - "CIDR value '{}' is > network bit count '{}'", - cdirNetwork.second, - ipaddress::kIPV4Bits)); + "Cannot cast value to IPPREFIX: {}", ipprefixString)); } auto ipv4Addr = folly::IPAddress::createIPv4(cdirNetwork.first); auto ipv4AddrWithMask = ipv4Addr.mask(cdirNetwork.second); @@ -132,9 +92,7 @@ tryParseIpPrefixString(folly::StringPiece ipprefixString) { threadSkipErrorDetails() ? Status::UserError() : Status::UserError( - "CIDR value '{}' is > network bit count '{}'", - cdirNetwork.second, - ipaddress::kIPV6Bits)); + "Cannot cast value to IPPREFIX: {}", ipprefixString)); } auto ipv6Addr = folly::IPAddress::createIPv6(cdirNetwork.first); auto ipv6AddrWithMask = ipv6Addr.mask(cdirNetwork.second);