1*61c4878aSAndroid Build Coastguard Worker // Copyright 2021 The Pigweed Authors
2*61c4878aSAndroid Build Coastguard Worker //
3*61c4878aSAndroid Build Coastguard Worker // Licensed under the Apache License, Version 2.0 (the "License"); you may not
4*61c4878aSAndroid Build Coastguard Worker // use this file except in compliance with the License. You may obtain a copy of
5*61c4878aSAndroid Build Coastguard Worker // the License at
6*61c4878aSAndroid Build Coastguard Worker //
7*61c4878aSAndroid Build Coastguard Worker // https://www.apache.org/licenses/LICENSE-2.0
8*61c4878aSAndroid Build Coastguard Worker //
9*61c4878aSAndroid Build Coastguard Worker // Unless required by applicable law or agreed to in writing, software
10*61c4878aSAndroid Build Coastguard Worker // distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
11*61c4878aSAndroid Build Coastguard Worker // WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
12*61c4878aSAndroid Build Coastguard Worker // License for the specific language governing permissions and limitations under
13*61c4878aSAndroid Build Coastguard Worker // the License.
14*61c4878aSAndroid Build Coastguard Worker
15*61c4878aSAndroid Build Coastguard Worker #include "pw_router/static_router.h"
16*61c4878aSAndroid Build Coastguard Worker
17*61c4878aSAndroid Build Coastguard Worker #include "pw_assert/check.h"
18*61c4878aSAndroid Build Coastguard Worker #include "pw_router/egress_function.h"
19*61c4878aSAndroid Build Coastguard Worker #include "pw_unit_test/framework.h"
20*61c4878aSAndroid Build Coastguard Worker
21*61c4878aSAndroid Build Coastguard Worker namespace pw::router {
22*61c4878aSAndroid Build Coastguard Worker namespace {
23*61c4878aSAndroid Build Coastguard Worker
24*61c4878aSAndroid Build Coastguard Worker struct BasicPacket {
25*61c4878aSAndroid Build Coastguard Worker static constexpr uint32_t kMagic = 0x8badf00d;
26*61c4878aSAndroid Build Coastguard Worker
BasicPacketpw::router::__anone2f307ac0111::BasicPacket27*61c4878aSAndroid Build Coastguard Worker constexpr BasicPacket(uint32_t addr, uint64_t data)
28*61c4878aSAndroid Build Coastguard Worker : magic(kMagic), address(addr), priority(0), payload(data) {}
29*61c4878aSAndroid Build Coastguard Worker
BasicPacketpw::router::__anone2f307ac0111::BasicPacket30*61c4878aSAndroid Build Coastguard Worker constexpr BasicPacket(uint32_t addr, uint32_t prio, uint64_t data)
31*61c4878aSAndroid Build Coastguard Worker : magic(kMagic), address(addr), priority(prio), payload(data) {}
32*61c4878aSAndroid Build Coastguard Worker
datapw::router::__anone2f307ac0111::BasicPacket33*61c4878aSAndroid Build Coastguard Worker ConstByteSpan data() const { return as_bytes(span(this, 1)); }
34*61c4878aSAndroid Build Coastguard Worker
35*61c4878aSAndroid Build Coastguard Worker uint32_t magic;
36*61c4878aSAndroid Build Coastguard Worker uint32_t address;
37*61c4878aSAndroid Build Coastguard Worker uint32_t priority;
38*61c4878aSAndroid Build Coastguard Worker uint64_t payload;
39*61c4878aSAndroid Build Coastguard Worker };
40*61c4878aSAndroid Build Coastguard Worker
41*61c4878aSAndroid Build Coastguard Worker class BasicPacketParser : public PacketParser {
42*61c4878aSAndroid Build Coastguard Worker public:
BasicPacketParser()43*61c4878aSAndroid Build Coastguard Worker constexpr BasicPacketParser() : packet_(nullptr) {}
44*61c4878aSAndroid Build Coastguard Worker
Parse(pw::ConstByteSpan packet)45*61c4878aSAndroid Build Coastguard Worker bool Parse(pw::ConstByteSpan packet) final {
46*61c4878aSAndroid Build Coastguard Worker packet_ = reinterpret_cast<const BasicPacket*>(packet.data());
47*61c4878aSAndroid Build Coastguard Worker return packet_->magic == BasicPacket::kMagic;
48*61c4878aSAndroid Build Coastguard Worker }
49*61c4878aSAndroid Build Coastguard Worker
GetDestinationAddress() const50*61c4878aSAndroid Build Coastguard Worker std::optional<uint32_t> GetDestinationAddress() const final {
51*61c4878aSAndroid Build Coastguard Worker PW_DCHECK_NOTNULL(packet_);
52*61c4878aSAndroid Build Coastguard Worker return packet_->address;
53*61c4878aSAndroid Build Coastguard Worker }
54*61c4878aSAndroid Build Coastguard Worker
priority() const55*61c4878aSAndroid Build Coastguard Worker uint32_t priority() const {
56*61c4878aSAndroid Build Coastguard Worker PW_DCHECK_NOTNULL(packet_);
57*61c4878aSAndroid Build Coastguard Worker return packet_->priority;
58*61c4878aSAndroid Build Coastguard Worker }
59*61c4878aSAndroid Build Coastguard Worker
60*61c4878aSAndroid Build Coastguard Worker private:
61*61c4878aSAndroid Build Coastguard Worker const BasicPacket* packet_;
62*61c4878aSAndroid Build Coastguard Worker };
63*61c4878aSAndroid Build Coastguard Worker
__anone2f307ac0202(ConstByteSpan, const PacketParser&) 64*61c4878aSAndroid Build Coastguard Worker EgressFunction GoodEgress(+[](ConstByteSpan, const PacketParser&) {
65*61c4878aSAndroid Build Coastguard Worker return OkStatus();
66*61c4878aSAndroid Build Coastguard Worker });
__anone2f307ac0302(ConstByteSpan, const PacketParser&) 67*61c4878aSAndroid Build Coastguard Worker EgressFunction BadEgress(+[](ConstByteSpan, const PacketParser&) {
68*61c4878aSAndroid Build Coastguard Worker return Status::ResourceExhausted();
69*61c4878aSAndroid Build Coastguard Worker });
70*61c4878aSAndroid Build Coastguard Worker
TEST(StaticRouter,RoutePacket_RoutesToAnEgress)71*61c4878aSAndroid Build Coastguard Worker TEST(StaticRouter, RoutePacket_RoutesToAnEgress) {
72*61c4878aSAndroid Build Coastguard Worker BasicPacketParser parser;
73*61c4878aSAndroid Build Coastguard Worker constexpr StaticRouter::Route routes[] = {{1, GoodEgress}, {2, BadEgress}};
74*61c4878aSAndroid Build Coastguard Worker StaticRouter router(routes);
75*61c4878aSAndroid Build Coastguard Worker
76*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.RoutePacket(BasicPacket(1, 0xdddd).data(), parser),
77*61c4878aSAndroid Build Coastguard Worker OkStatus());
78*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.RoutePacket(BasicPacket(2, 0xdddd).data(), parser),
79*61c4878aSAndroid Build Coastguard Worker Status::Unavailable());
80*61c4878aSAndroid Build Coastguard Worker }
81*61c4878aSAndroid Build Coastguard Worker
TEST(StaticRouter,RoutePacket_ForwardsPacketParser)82*61c4878aSAndroid Build Coastguard Worker TEST(StaticRouter, RoutePacket_ForwardsPacketParser) {
83*61c4878aSAndroid Build Coastguard Worker uint32_t parser_priority = 0xffffffff;
84*61c4878aSAndroid Build Coastguard Worker
85*61c4878aSAndroid Build Coastguard Worker EgressFunction parser_egress(
86*61c4878aSAndroid Build Coastguard Worker [&parser_priority](ConstByteSpan, const PacketParser& parser) {
87*61c4878aSAndroid Build Coastguard Worker const BasicPacketParser& basic_parser =
88*61c4878aSAndroid Build Coastguard Worker static_cast<const BasicPacketParser&>(parser);
89*61c4878aSAndroid Build Coastguard Worker parser_priority = basic_parser.priority();
90*61c4878aSAndroid Build Coastguard Worker return OkStatus();
91*61c4878aSAndroid Build Coastguard Worker });
92*61c4878aSAndroid Build Coastguard Worker
93*61c4878aSAndroid Build Coastguard Worker StaticRouter::Route routes[] = {{1, parser_egress}};
94*61c4878aSAndroid Build Coastguard Worker StaticRouter router(routes);
95*61c4878aSAndroid Build Coastguard Worker BasicPacketParser parser;
96*61c4878aSAndroid Build Coastguard Worker
97*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.RoutePacket(BasicPacket(1, 71, 0xdddd).data(), parser),
98*61c4878aSAndroid Build Coastguard Worker OkStatus());
99*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(parser_priority, 71u);
100*61c4878aSAndroid Build Coastguard Worker }
101*61c4878aSAndroid Build Coastguard Worker
TEST(StaticRouter,RoutePacket_ReturnsParserError)102*61c4878aSAndroid Build Coastguard Worker TEST(StaticRouter, RoutePacket_ReturnsParserError) {
103*61c4878aSAndroid Build Coastguard Worker BasicPacketParser parser;
104*61c4878aSAndroid Build Coastguard Worker constexpr StaticRouter::Route routes[] = {{1, GoodEgress}, {2, BadEgress}};
105*61c4878aSAndroid Build Coastguard Worker StaticRouter router(routes);
106*61c4878aSAndroid Build Coastguard Worker
107*61c4878aSAndroid Build Coastguard Worker BasicPacket bad_magic(1, 0xdddd);
108*61c4878aSAndroid Build Coastguard Worker bad_magic.magic = 0x1badda7a;
109*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.RoutePacket(bad_magic.data(), parser), Status::DataLoss());
110*61c4878aSAndroid Build Coastguard Worker }
111*61c4878aSAndroid Build Coastguard Worker
TEST(StaticRouter,RoutePacket_ReturnsNotFoundOnInvalidRoute)112*61c4878aSAndroid Build Coastguard Worker TEST(StaticRouter, RoutePacket_ReturnsNotFoundOnInvalidRoute) {
113*61c4878aSAndroid Build Coastguard Worker BasicPacketParser parser;
114*61c4878aSAndroid Build Coastguard Worker constexpr StaticRouter::Route routes[] = {{1, GoodEgress}, {2, BadEgress}};
115*61c4878aSAndroid Build Coastguard Worker StaticRouter router(routes);
116*61c4878aSAndroid Build Coastguard Worker
117*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.RoutePacket(BasicPacket(42, 0xdddd).data(), parser),
118*61c4878aSAndroid Build Coastguard Worker Status::NotFound());
119*61c4878aSAndroid Build Coastguard Worker }
120*61c4878aSAndroid Build Coastguard Worker
TEST(StaticRouter,RoutePacket_TracksNumberOfDrops)121*61c4878aSAndroid Build Coastguard Worker TEST(StaticRouter, RoutePacket_TracksNumberOfDrops) {
122*61c4878aSAndroid Build Coastguard Worker BasicPacketParser parser;
123*61c4878aSAndroid Build Coastguard Worker constexpr StaticRouter::Route routes[] = {{1, GoodEgress}, {2, BadEgress}};
124*61c4878aSAndroid Build Coastguard Worker StaticRouter router(routes);
125*61c4878aSAndroid Build Coastguard Worker
126*61c4878aSAndroid Build Coastguard Worker // Good
127*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.RoutePacket(BasicPacket(1, 0xdddd).data(), parser),
128*61c4878aSAndroid Build Coastguard Worker OkStatus());
129*61c4878aSAndroid Build Coastguard Worker
130*61c4878aSAndroid Build Coastguard Worker // Egress error
131*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.RoutePacket(BasicPacket(2, 0xdddd).data(), parser),
132*61c4878aSAndroid Build Coastguard Worker Status::Unavailable());
133*61c4878aSAndroid Build Coastguard Worker
134*61c4878aSAndroid Build Coastguard Worker // Parser error
135*61c4878aSAndroid Build Coastguard Worker BasicPacket bad_magic(1, 0xdddd);
136*61c4878aSAndroid Build Coastguard Worker bad_magic.magic = 0x1badda7a;
137*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.RoutePacket(bad_magic.data(), parser), Status::DataLoss());
138*61c4878aSAndroid Build Coastguard Worker
139*61c4878aSAndroid Build Coastguard Worker // Good
140*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.RoutePacket(BasicPacket(1, 0xdddd).data(), parser),
141*61c4878aSAndroid Build Coastguard Worker OkStatus());
142*61c4878aSAndroid Build Coastguard Worker
143*61c4878aSAndroid Build Coastguard Worker // Bad route
144*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.RoutePacket(BasicPacket(42, 0xdddd).data(), parser),
145*61c4878aSAndroid Build Coastguard Worker Status::NotFound());
146*61c4878aSAndroid Build Coastguard Worker
147*61c4878aSAndroid Build Coastguard Worker EXPECT_EQ(router.dropped_packets(), 3u);
148*61c4878aSAndroid Build Coastguard Worker }
149*61c4878aSAndroid Build Coastguard Worker
150*61c4878aSAndroid Build Coastguard Worker } // namespace
151*61c4878aSAndroid Build Coastguard Worker } // namespace pw::router
152