Skip to content

Commit

Permalink
[P4 Constraints Network Address Notation] Update parser to support ip…
Browse files Browse the repository at this point in the history
…v6 addresses. (#134)

PiperOrigin-RevId: 605442789

Co-authored-by: PINS Team <[email protected]>
  • Loading branch information
matthewtlam and PINS Team authored Feb 17, 2024
1 parent fc97f32 commit added57
Show file tree
Hide file tree
Showing 2 changed files with 92 additions and 2 deletions.
33 changes: 31 additions & 2 deletions p4_constraints/frontend/ast_constructors.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@

#include "p4_constraints/frontend/ast_constructors.h"

#include <arpa/inet.h>
#include <gmpxx.h>

#include <bitset>
Expand Down Expand Up @@ -173,6 +174,30 @@ absl::StatusOr<std::string> Ipv4StringToByteString(
return bits.to_string();
}

template <std::size_t num_bits>
std::bitset<num_bits> AnyByteStringToBitset(
const absl::string_view& byte_string) {
std::bitset<num_bits> bits;
for (char c : byte_string) {
uint8_t byte = 0;
memcpy(&byte, &c, 1);
bits <<= 8;
bits |= byte;
}
return bits;
}

absl::StatusOr<std::string> 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<std::string> MacStringToByteString(
const absl::string_view& mac_address) {
std::vector<std::string> bytes = absl::StrSplit(mac_address, ':');
Expand All @@ -192,6 +217,7 @@ absl::StatusOr<std::string> MacStringToByteString(
}
return bits.to_string();
}

// -- Auxiliary base constructors ----------------------------------------------

ast::Expression LocatedExpression(const ast::SourceLocation& start_location,
Expand Down Expand Up @@ -236,8 +262,11 @@ absl::StatusOr<ast::Expression> 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));
Expand Down
61 changes: 61 additions & 0 deletions p4_constraints/frontend/parser_test.cc
Original file line number Diff line number Diff line change
Expand Up @@ -409,4 +409,65 @@ TEST_F(ParserTest, FailsToParseInvalidMacAddress) {
StatusIs(absl::StatusCode::kInvalidArgument));
}

TEST_F(ParserTest, ParseIpv6Address) {
std::vector<Token> 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<Token> 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<Token> 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<Token> 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<Token> 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<Token> 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<Token> 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<Token> 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

0 comments on commit added57

Please sign in to comment.