Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions packetlib/bit_widths.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,7 @@ constexpr int kPtpHeaderBitwidth = 272;
constexpr int kPspHeaderBitwidth = 128;
constexpr int kIbBthHeaderBitwidth = 96;
constexpr int kCsigHeaderBitwidth = 32;
constexpr int kCsigWideHeaderBitwidth = 64;

// Ethernet constants.
constexpr int kEthernetEthertypeBitwidth = 16;
Expand All @@ -55,6 +56,13 @@ constexpr int kCsigSignalValueBitwidth = 5;
constexpr int kCsigLocatorMetadataBitwidth = 7;
constexpr int kCsigEthertypeBitwidth = 16;

// CSIG Wide constants.
constexpr int kCsigWideLocatorMetadataBitwidth = 16;
constexpr int kCsigWideSignalTypeBitwidth = 4;
constexpr int kCsigWideSignalValueBitwidth = 20;
constexpr int kCsigWideReservedBitwidth = 8;
constexpr int kCsigWideEthertypeBitwidth = 16;

// IP constants.
constexpr int kIpVersionBitwidth = 4; // IPv4 & IPv6
constexpr int kIpIhlBitwidth = 4; // IPv4
Expand Down
81 changes: 80 additions & 1 deletion packetlib/packetlib.cc
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,7 @@ absl::StatusOr<NextHeader> GetNextHeaderForEtherType(
if (ethertype == 0x8100) return Header::kVlanHeader;
if (ethertype == 0x88f7) return Header::kPtpHeader;
if (ethertype == 0x9900) return Header::kCsigHeader;
if (ethertype == 0x9901) return Header::kCsigWideHeader;
return UnsupportedNextHeader{
.reason = absl::StrFormat("%s.ethertype %s: unsupported", header_name,
ethertype_hexstring)};
Expand All @@ -97,6 +98,9 @@ absl::StatusOr<NextHeader> GetNextHeader(const VlanHeader& header) {
absl::StatusOr<NextHeader> GetNextHeader(const CsigHeader& header) {
return GetNextHeaderForEtherType("csig_header", header.ethertype());
}
absl::StatusOr<NextHeader> GetNextHeader(const CsigWideHeader& header) {
return GetNextHeaderForEtherType("csig_wide_header", header.ethertype());
}
absl::StatusOr<NextHeader> GetNextHeader(const GreHeader& header) {
return GetNextHeaderForEtherType("gre_header", header.protocol_type());
}
Expand Down Expand Up @@ -221,6 +225,8 @@ absl::StatusOr<NextHeader> GetNextHeader(const Header& header) {
return GetNextHeader(header.vlan_header());
case Header::kCsigHeader:
return GetNextHeader(header.csig_header());
case Header::kCsigWideHeader:
return GetNextHeader(header.csig_wide_header());
case Header::kGreHeader:
return GetNextHeader(header.gre_header());
case Header::kSaiP4Bmv2PacketInHeader:
Expand Down Expand Up @@ -519,6 +525,26 @@ absl::StatusOr<CsigHeader> ParseCsigHeader(string_encodings::BitString& data) {
return header;
}

// Parse a CsigWide header, or return error if the packet is too small.
absl::StatusOr<CsigWideHeader> ParseCsigWideHeader(
string_encodings::BitString& data) {
if (data.size() < kCsigWideHeaderBitwidth) {
return gutil::InvalidArgumentErrorBuilder()
<< "Packet is too short to parse a CsigWide header next. Only "
<< data.size() << " bits left, need at least "
<< kCsigWideHeaderBitwidth << ".";
}

CsigWideHeader header;
header.set_locator_metadata(
ParseBits(data, kCsigWideLocatorMetadataBitwidth));
header.set_signal_type(ParseBits(data, kCsigWideSignalTypeBitwidth));
header.set_signal_value(ParseBits(data, kCsigWideSignalValueBitwidth));
header.set_reserved(ParseBits(data, kCsigWideReservedBitwidth));
header.set_ethertype(ParseBits(data, kCsigWideEthertypeBitwidth));
return header;
}

// Parse a GRE header, or return error if the packet is too small.
absl::StatusOr<GreHeader> ParseGreHeader(string_encodings::BitString& data) {
int size = kRfc2784GreHeaderWithoutOptionalsBitwidth;
Expand Down Expand Up @@ -752,6 +778,11 @@ absl::StatusOr<Header> ParseHeader(Header::HeaderCase header_case,
ASSIGN_OR_RETURN(*result.mutable_csig_header(), ParseCsigHeader(data));
return result;
}
case Header::kCsigWideHeader: {
ASSIGN_OR_RETURN(*result.mutable_csig_wide_header(),
ParseCsigWideHeader(data));
return result;
}
case Header::kGreHeader: {
ASSIGN_OR_RETURN(*result.mutable_gre_header(), ParseGreHeader(data));
return result;
Expand Down Expand Up @@ -1480,6 +1511,24 @@ void CsigHeaderInvalidReasons(const CsigHeader& header,
header.ethertype(), absl::StrCat(field_prefix, "ethertype"), output);
}

void CsigWideHeaderInvalidReasons(const CsigWideHeader& header,
const std::string& field_prefix,
const Packet& packet, int header_index,
std::vector<std::string>& output) {
HexStringInvalidReasons<kCsigWideLocatorMetadataBitwidth>(
header.locator_metadata(), absl::StrCat(field_prefix, "locator_metadata"),
output);
HexStringInvalidReasons<kCsigWideSignalTypeBitwidth>(
header.signal_type(), absl::StrCat(field_prefix, "signal_type"), output);
HexStringInvalidReasons<kCsigWideSignalValueBitwidth>(
header.signal_value(), absl::StrCat(field_prefix, "signal_value"),
output);
HexStringInvalidReasons<kCsigWideReservedBitwidth>(
header.reserved(), absl::StrCat(field_prefix, "reserved"), output);
HexStringInvalidReasons<kCsigWideEthertypeBitwidth>(
header.ethertype(), absl::StrCat(field_prefix, "ethertype"), output);
}

void GreHeaderInvalidReasons(const GreHeader& header,
const std::string& field_prefix,
const Packet& packet, int header_index,
Expand Down Expand Up @@ -1894,6 +1943,8 @@ std::string HeaderCaseName(Header::HeaderCase header_case) {
return "VlanHeader";
case Header::kCsigHeader:
return "CsigHeader";
case Header::kCsigWideHeader:
return "CsigWideHeader";
case Header::kGreHeader:
return "GreHeader";
case Header::kSaiP4Bmv2PacketInHeader:
Expand Down Expand Up @@ -1929,7 +1980,8 @@ absl::StatusOr<std::string> GetEthernetTrailer(const Packet& packet) {
int header_index = 1;
while (header_index < packet.headers().size() &&
(packet.headers(header_index).has_vlan_header() ||
packet.headers(header_index).has_csig_header())) {
packet.headers(header_index).has_csig_header() ||
packet.headers(header_index).has_csig_wide_header())) {
++header_index;
}
if (header_index >= packet.headers().size()) {
Expand Down Expand Up @@ -2061,6 +2113,11 @@ std::vector<std::string> PacketInvalidReasons(const Packet& packet) {
index, result);
break;
}
case Header::kCsigWideHeader: {
CsigWideHeaderInvalidReasons(header.csig_wide_header(), error_prefix,
packet, index, result);
break;
}
case Header::kGreHeader: {
GreHeaderInvalidReasons(header.gre_header(), error_prefix, packet,
index, result);
Expand Down Expand Up @@ -2324,6 +2381,21 @@ absl::Status SerializeCsigHeader(const CsigHeader& header,
return absl::OkStatus();
}

absl::Status SerializeCsigWideHeader(const CsigWideHeader& header,
string_encodings::BitString& output) {
RETURN_IF_ERROR(SerializeBits<kCsigWideLocatorMetadataBitwidth>(
header.locator_metadata(), output));
RETURN_IF_ERROR(
SerializeBits<kCsigWideSignalTypeBitwidth>(header.signal_type(), output));
RETURN_IF_ERROR(SerializeBits<kCsigWideSignalValueBitwidth>(
header.signal_value(), output));
RETURN_IF_ERROR(
SerializeBits<kCsigWideReservedBitwidth>(header.reserved(), output));
RETURN_IF_ERROR(
SerializeBits<kCsigWideEthertypeBitwidth>(header.ethertype(), output));
return absl::OkStatus();
}

absl::Status SerializeGreHeader(const GreHeader& header,
string_encodings::BitString& output) {
RETURN_IF_ERROR(SerializeBits<kGreChecksumPresentBitwidth>(
Expand Down Expand Up @@ -2512,6 +2584,8 @@ absl::Status SerializeHeader(const Header& header,
return SerializeIbBthHeader(header.ib_bth_header(), output);
case Header::kCsigHeader:
return SerializeCsigHeader(header.csig_header(), output);
case Header::kCsigWideHeader:
return SerializeCsigWideHeader(header.csig_wide_header(), output);
case Header::HEADER_NOT_SET:
return gutil::InvalidArgumentErrorBuilder()
<< "Found invalid HEADER_NOT_SET in header.";
Expand Down Expand Up @@ -2915,6 +2989,7 @@ absl::StatusOr<bool> UpdateComputedFields(Packet& packet, bool overwrite) {
}
case Header::kVlanHeader:
case Header::kCsigHeader:
case Header::kCsigWideHeader:
case Header::kPspHeader: {
// No computed fields.
break;
Expand Down Expand Up @@ -2970,6 +3045,7 @@ absl::StatusOr<bool> PadPacketToMinimumSizeFromHeaderIndex(Packet& packet,
case Header::kPspHeader:
case Header::kIbBthHeader:
case Header::kCsigHeader:
case Header::kCsigWideHeader:
return PadPacketToMinimumSizeFromHeaderIndex(packet, header_index + 1);
case Header::HEADER_NOT_SET:
return false;
Expand Down Expand Up @@ -3086,6 +3162,9 @@ absl::StatusOr<int> PacketSizeInBits(const Packet& packet,
case Header::kCsigHeader:
size += kCsigHeaderBitwidth;
break;
case Header::kCsigWideHeader:
size += kCsigWideHeaderBitwidth;
break;
case Header::HEADER_NOT_SET:
return gutil::InvalidArgumentErrorBuilder()
<< "Found invalid HEADER_NOT_SET in header.";
Expand Down
10 changes: 10 additions & 0 deletions packetlib/packetlib.proto
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ message Header {
CsigHeader csig_header = 15;
HopByHopOptionsHeader hop_by_hop_options_header = 16;
IbBthHeader ib_bth_header = 17;
CsigWideHeader csig_wide_header = 18;
}
}

Expand Down Expand Up @@ -100,6 +101,15 @@ message CsigHeader {
string ethertype = 5; // 16 bits
}

// A CsigWide header.
message CsigWideHeader {
string locator_metadata = 1; // 16 bits
string signal_type = 2; // 4 bits
string signal_value = 3; // 20 bits
string reserved = 4; // 8 bits
string ethertype = 5; // 16 bits
}

// An ARP header.
// It is assumed to be used with Ethernet and IPv4.
message ArpHeader {
Expand Down
52 changes: 52 additions & 0 deletions packetlib/packetlib_test_runner.cc
Original file line number Diff line number Diff line change
Expand Up @@ -718,6 +718,39 @@ void RunPacketParseTests() {
# other headers:
payload: 0x12
)pb");
RunPacketParseTest("CSIG Wide IPv6 packet (valid)", R"pb(
# ethernet header
ethernet_destination: 0xaabbccddeeff
ethernet_source: 0x112233445566
ether_type: 0x9901
# CSIG Wide header
locator_metadata: 0x1234
signal_type: 0x1
signal_value: 0x12345
reserved: 0x00
ethertype: 0x86dd
# IPv6 header:
version: 0x6
dscp: 0b011011
ecn: 0b01
flow_label: 0x12345
payload_length: 0x0010
next_header: 0xfd # Reserved for experimentation -- payload is arbitrary.
hop_limit: 0x03
ipv6_source: 0x00001111222233334444555566667777
ipv6_destination: 0x88889999aaaabbbbccccddddeeeeffff
# other headers:
payload: 0x00 11 22 33 44 55 66 77 88 99 aa bb cc dd ee ff
)pb");
RunPacketParseTest("CSIG Wide IPv6 packet (invalid length)", R"pb(
# ethernet header
ethernet_destination: 0xaabbccddeeff
ethernet_source: 0x112233445566
ether_type: 0x9901
# CSIG Wide header (only 24 bits provided, 64 needed)
locator_metadata: 0x1234
signal_type: 0x01
)pb");
RunPacketParseTest("PTP in L2 packet (valid)",
R"pb(
# Ethernet header.
Expand Down Expand Up @@ -3142,6 +3175,25 @@ void RunProtoPacketTests() {
}
payload: "ABCDABCDABCDABCDABCD" # 20 octets
)pb"));
RunProtoPacketTest("CSIG Wide packet (invalid field values)",
gutil::ParseProtoOrDie<Packet>(R"pb(
headers {
ethernet_header {
ethernet_destination: "aa:bb:cc:dd:ee:ff"
ethernet_source: "11:22:33:44:55:66"
ethertype: "0x9901"
}
}
headers {
csig_wide_header {
locator_metadata: "0x12345" # 20 bits, expected 16
signal_type: "0x12" # 8 bits, expected 4
signal_value: "0x123456" # 24 bits, expected 20
reserved: "0x123" # 12 bits, expected 8
ethertype: "0x86dd1" # 20 bits, expected 16
}
}
)pb"));
} // NOLINT(readability/fn_size)

void main() {
Expand Down
Loading
Loading