diff --git a/p4_constraints/frontend/ast_constructors.cc b/p4_constraints/frontend/ast_constructors.cc index bf66c78..b280b29 100644 --- a/p4_constraints/frontend/ast_constructors.cc +++ b/p4_constraints/frontend/ast_constructors.cc @@ -14,6 +14,7 @@ #include "p4_constraints/frontend/ast_constructors.h" +#include #include #include @@ -173,6 +174,30 @@ absl::StatusOr Ipv4StringToByteString( return bits.to_string(); } +template +std::bitset AnyByteStringToBitset( + const absl::string_view& byte_string) { + std::bitset bits; + for (char c : byte_string) { + uint8_t byte = 0; + memcpy(&byte, &c, 1); + bits <<= 8; + bits |= byte; + } + return bits; +} + +absl::StatusOr Ipv6StringToByteString( + const absl::string_view& ipv6_address) { + std::string bytes = std::string(128 / 8, '\x0'); + if (inet_pton(10, ipv6_address.data(), bytes.data()) == 1) { + auto ip = AnyByteStringToBitset<128>(bytes); + return ip.to_string(); + } + return gutils::InvalidArgumentErrorBuilder(GUTILS_LOC) + << absl::StreamFormat("Invalid Ipv6 address: %s", ipv6_address); +} + absl::StatusOr MacStringToByteString( const absl::string_view& mac_address) { std::vector bytes = absl::StrSplit(mac_address, ':'); @@ -192,6 +217,7 @@ absl::StatusOr MacStringToByteString( } return bits.to_string(); } + // -- Auxiliary base constructors ---------------------------------------------- ast::Expression LocatedExpression(const ast::SourceLocation& start_location, @@ -236,8 +262,11 @@ absl::StatusOr MakeNetworkAddressIntegerConstant( ConvertNumeral(Token(Token::BINARY, ipv4_bits, start_location, end_location))); } else if (address_type == "ipv6") { - return absl::UnimplementedError( - "IPv6 addresses are not currently supported"); + ASSIGN_OR_RETURN(std::string ipv6_bytes, + Ipv6StringToByteString(address_string)); + ASSIGN_OR_RETURN(numeral_str, + ConvertNumeral(Token(Token::BINARY, ipv6_bytes, + start_location, end_location))); } else if (address_type == "mac") { ASSIGN_OR_RETURN(std::string mac_bytes, MacStringToByteString(address_string)); diff --git a/p4_constraints/frontend/parser_test.cc b/p4_constraints/frontend/parser_test.cc index cb77f95..5024de9 100644 --- a/p4_constraints/frontend/parser_test.cc +++ b/p4_constraints/frontend/parser_test.cc @@ -409,4 +409,65 @@ TEST_F(ParserTest, FailsToParseInvalidMacAddress) { StatusIs(absl::StatusCode::kInvalidArgument)); } +TEST_F(ParserTest, ParseIpv6Address) { + std::vector zero_ipv6_tokens = {Id("ipv6"), kLpar, String("::"), + kRpar}; + EXPECT_THAT( + internal_parser::ParseConstraint(ConstraintKind::kTableConstraint, + zero_ipv6_tokens, kDummySource), + IsOkAndHolds(Partially(EqualsProto(R"pb(integer_constant: "0")pb")))); + + std::vector full_ipv6_tokens = { + Id("ipv6"), kLpar, String("0000:0000:0000:0000:0000:0000:0000:0009"), + kRpar}; + EXPECT_THAT( + internal_parser::ParseConstraint(ConstraintKind::kTableConstraint, + full_ipv6_tokens, kDummySource), + IsOkAndHolds(Partially(EqualsProto(R"pb(integer_constant: "9")pb")))); + + std::vector zero_start_ipv6_tokens = {Id("ipv6"), kLpar, + String("::0000:0005"), kRpar}; + EXPECT_THAT( + internal_parser::ParseConstraint(ConstraintKind::kTableConstraint, + zero_start_ipv6_tokens, kDummySource), + IsOkAndHolds(Partially(EqualsProto(R"pb(integer_constant: "5")pb")))); + + std::vector zero_middle_ipv6_tokens = { + Id("ipv6"), kLpar, String("0000:0000::0000:4"), kRpar}; + EXPECT_THAT( + internal_parser::ParseConstraint(ConstraintKind::kTableConstraint, + zero_middle_ipv6_tokens, kDummySource), + IsOkAndHolds(Partially(EqualsProto(R"pb(integer_constant: "4")pb")))); + + std::vector zero_end_ipv6_tokens = {Id("ipv6"), kLpar, + String("0000:0000::"), kRpar}; + EXPECT_THAT( + internal_parser::ParseConstraint(ConstraintKind::kTableConstraint, + zero_end_ipv6_tokens, kDummySource), + IsOkAndHolds(Partially(EqualsProto(R"pb(integer_constant: "0")pb")))); +} + +TEST_F(ParserTest, FailsToParseInvalidIpv6Address) { + std::vector illegal_ipv6_tokens = { + Id("ipv6"), kLpar, String("2001:db8::lmno:5678"), kRpar}; + EXPECT_THAT( + internal_parser::ParseConstraint(ConstraintKind::kTableConstraint, + illegal_ipv6_tokens, kDummySource), + StatusIs(absl::StatusCode::kInvalidArgument)); + + std::vector long_illegal_ipv6_tokens = { + Id("ipv6"), kLpar, + String("2001:db8:3333:4444:5555:6666:7777:8888:5000:5000:5000"), kRpar}; + EXPECT_THAT( + internal_parser::ParseConstraint(ConstraintKind::kTableConstraint, + long_illegal_ipv6_tokens, kDummySource), + StatusIs(absl::StatusCode::kInvalidArgument)); + + std::vector extra_colons_ipv6_tokens = {Id("ipv6"), kLpar, + String(":::"), kRpar}; + EXPECT_THAT( + internal_parser::ParseConstraint(ConstraintKind::kTableConstraint, + extra_colons_ipv6_tokens, kDummySource), + StatusIs(absl::StatusCode::kInvalidArgument)); +} } // namespace p4_constraints