pw_router#

Transport-agnostic packet routing

Experimental C++

The pw_router module provides transport-agnostic classes for routing packets over network links.

Common router interfaces#

PacketParser#

To work with arbitrary packet formats, routers require a common interface for extracting relevant packet data, such as the destination. This interface is pw::router::PacketParser, defined in pw_router/packet_parser.h, which must be implemented for the packet framing format used by the network.

Egress#

The Egress class is a virtual interface for sending packet data over a network link. Egress implementations provide a single SendPacket function, which takes the raw packet data and transmits it.

Egresses are invoked with the PacketParser used to process the packet. This allows additional information to be extracted from each packet to assist with transmitting decisions. For example, if packets in a project include a priority, egresses may use it to provide quality-of-service by dropping certain packets under heavy load.

Status MyEgress::SendPacket(
    ConstByteSpan packet, const PacketParser& parser) override {
  // Downcast the base PacketParser to the custom implementation that was
  // passed into RoutePacket().
  const CustomPacketParser& custom_parser =
      static_cast<const CustomPacketParser&>(parser);

  // Custom packet fields can now be accessed if necessary.
  if (custom_parser.priority() == MyPacketPriority::kHigh) {
    return SendHighPriorityPacket(packet);
  }

  return SendStandardPriorityPacket(packet);
}

Some common egress implementations are provided upstream in Pigweed.

StaticRouter#

pw::router::StaticRouter is a router with a static table of address to egress mappings. Routes in a static router never change; packets with the same address are always sent through the same egress. If links are unavailable, packets will be dropped.

Static routers are suitable for basic networks with persistent links.

Usage example#

namespace {

// Define the router egresses.
UartEgress uart_egress;
BluetoothEgress ble_egress;

// Define the routing table.
constexpr pw::router::StaticRouter::Route routes[] = {{1, uart_egress},
                                                      {7, ble_egress}};
pw::router::StaticRouter router(routes);

}  // namespace

void ProcessPacket(pw::ConstByteSpan packet) {
  HdlcFrameParser hdlc_parser;
  router.RoutePacket(packet, hdlc_parser);
}

Size report#

The following size report shows the cost of a StaticRouter with a simple PacketParser implementation and a single route using an EgressFunction.

Label

Segment

Delta

Static router with a single route

FLASH

DEL

-596

__aeabi_dmul

DEL

-464

__aeabi_ddiv

+4

_ctype_

DEL

-160

__aeabi_d2f

DEL

-140

__gtdf2

-77

pw_assert_HandleFailure::_pw_tokenizer_string_entry_35_3

DEL

-120

pw::bloat::BloatThisBinary()

DEL

-80

__aeabi_d2iz

DEL

-72

main

+88

pw::bloat::BloatThisBinary()::_pw_tokenizer_string_entry_63_3

-49

pw_assert_tokenized_HandleAssertFailure::_pw_tokenizer_string_entry_60_5

DEL

-44

__aeabi_dcmpun

DEL

-32

__aeabi_cdrcmple

DEL

-20

__aeabi_dcmpeq

DEL

-20

__aeabi_dcmpge

DEL

-20

__aeabi_dcmpgt

DEL

-20

__aeabi_dcmple

DEL

-20

__aeabi_dcmplt

DEL

-17

__floatundidf

-2

pw_boot_PreMainInit

DEL

-2

pw_boot_PreStaticConstructorInit

NEW

+210

pw::router::StaticRouter::RoutePacket()

NEW

+173

pw::containers::internal::CheckIntrusiveItemIsUncontained()::_pw_tokenizer_string_entry_28_3

NEW

+167

pw::containers::internal::CheckIntrusiveContainerIsEmpty()::_pw_tokenizer_string_entry_22_1

NEW

+124

main::_pw_tokenizer_string_entry_81_25

NEW

+124

main::_pw_tokenizer_string_entry_93_33

NEW

+123

main::_pw_tokenizer_string_entry_89_29

NEW

+107

main::_pw_tokenizer_string_entry_77_21

NEW

+104

pw::metric::Metric::SetFloat()::_pw_tokenizer_string_entry_94_11

NEW

+104

pw::metric::Metric::as_float()::_pw_tokenizer_string_entry_65_1

NEW

+102

pw::metric::Metric::Decrement()::_pw_tokenizer_string_entry_82_7

NEW

+102

pw::metric::Metric::Increment()::_pw_tokenizer_string_entry_75_5

NEW

+102

pw::metric::Metric::SetInt()::_pw_tokenizer_string_entry_89_9

NEW

+102

pw::metric::Metric::as_int()::_pw_tokenizer_string_entry_70_3

NEW

+88

_GLOBAL__sub_I_static_router_with_one_route.cc

NEW

+81

pw::metric::Metric::Dump()::_pw_tokenizer_string_entry_109_15

NEW

+81

pw::metric::Metric::Dump()::_pw_tokenizer_string_entry_115_19

NEW

+77

pw::metric::Group::Dump()::_pw_tokenizer_string_entry_141_31

NEW

+73

pw::metric::Group::Dump()::_pw_tokenizer_string_entry_144_35

NEW

+69

pw::metric::Group::Dump()::_pw_tokenizer_string_entry_132_23

NEW

+69

pw::metric::Group::Dump()::_pw_tokenizer_string_entry_134_27

NEW

+48

__aeabi_f2d

NEW

+37

main::_pw_tokenizer_string_entry_77_19

NEW

+37

main::_pw_tokenizer_string_entry_81_23

NEW

+37

main::_pw_tokenizer_string_entry_89_27

NEW

+37

main::_pw_tokenizer_string_entry_93_31

NEW

+37

pw::metric::Group::Dump()::_pw_tokenizer_string_entry_132_21

NEW

+37

pw::metric::Group::Dump()::_pw_tokenizer_string_entry_134_25

NEW

+37

pw::metric::Group::Dump()::_pw_tokenizer_string_entry_141_29

NEW

+37

pw::metric::Group::Dump()::_pw_tokenizer_string_entry_144_33

NEW

+37

pw::metric::Metric::Dump()::_pw_tokenizer_string_entry_109_13

NEW

+37

pw::metric::Metric::Dump()::_pw_tokenizer_string_entry_115_17

NEW

+36

pw::metric::Metric::Increment()

NEW

+34

__aeabi_i2d

NEW

+33

__aeabi_dsub

NEW

+30

__aeabi_ui2d

NEW

+30

pw::containers::internal::GenericIntrusiveList<>::insert_after()

NEW

+28

__cxa_atexit

NEW

+24

(anonymous namespace)::BasicPacketParser

NEW

+24

pw_assert_tokenized_HandleCheckFailure

NEW

+20

(anonymous namespace)::BasicPacketParser::Parse()

NEW

+20

fit::internal::target<>::ops

NEW

+20

pw::containers::internal::CheckIntrusiveContainerIsEmpty()

NEW

+20

pw::containers::internal::CheckIntrusiveItemIsUncontained()

NEW

+20

pw::router::EgressFunction

NEW

+16

free

NEW

+16

pw::metric::Metric::Metric()

NEW

+14

OUTLINED_FUNCTION_0

NEW

+12

(anonymous namespace)::BasicPacketParser::GetDestinationAddress()

NEW

+10

(anonymous namespace)::$_0::__invoke()

NEW

+8

(anonymous namespace)::routes

NEW

+8

operator delete()

NEW

+6

(anonymous namespace)::BasicPacketParser::~BasicPacketParser()

NEW

+2

pw::router::StaticRouter::_pw_tokenizer_string_entry_66_1

NEW

+2

pw::router::StaticRouter::_pw_tokenizer_string_entry_67_3

NEW

+2

pw::router::StaticRouter::_pw_tokenizer_string_entry_68_5

+1,172

Zephyr#

To enable pw_router.* for Zephyr add CONFIG_PIGWEED_ROUTER=y to the project’s configuration. This will enable the Kconfig menu for the following:

  • pw_router.static_router which can be enabled via CONFIG_PIGWEED_ROUTER_STATIC_ROUTER=y.

  • pw_router.egress which can be enabled via CONFIG_PIGWEED_ROUTER_EGRESS=y.

  • pw_router.packet_parser which can be enabled via CONFIG_PIGWEED_ROUTER_PACKET_PARSER=y.

  • pw_router.egress_function which can be enabled via CONFIG_PIGWEED_ROUTER_EGRESS_FUNCTION=y.