7 #include <satcat5/ip_dispatch.h>
8 #include <satcat5/ip_icmp.h>
11 #include <satcat5/router2_deferfwd.h>
12 #include <satcat5/router2_dispatch.h>
13 #include <satcat5/router2_offload.h>
20 using satcat5::ip::checksum;
28 static constexpr
unsigned DEBUG_VERBOSE = 0;
30 Dispatch::Dispatch(u8* buff,
unsigned nbytes)
31 : SwitchCore(buff, nbytes)
42 return m_local_iface ? m_local_iface->ipaddr() : satcat5::ip::ADDR_NONE;
46 return m_local_iface ? m_local_iface->macaddr() : satcat5::eth::MACADDR_NONE;
50 if (m_local_iface) m_local_iface->set_ipaddr(addr);
57 if (!meta.read_from(packet)) {
58 debug_log(packet, SwitchLogMessage::DROP_BADFRM);
63 unsigned result = deliver_pkt(meta);
65 u8 reason = meta.reason()
66 ? meta.reason() : SwitchLogMessage::DROP_UNKNOWN;
92 if (plg_result)
return plg_result.value();
97 if (DEBUG_VERBOSE > 1)
Log(DEBUG,
"router.deliver.arp_out");
98 return deliver_arp(meta);
99 }
else if (meta.
is_arp()) {
102 if (DEBUG_VERBOSE > 1)
Log(DEBUG,
"router.deliver.arp_from").
write10((u32)meta.
src_port());
103 return deliver_local(meta);
104 }
else if (meta.
is_ip() && meta.
ip.
dst() == ipaddr()) {
106 if (DEBUG_VERBOSE > 1)
Log(DEBUG,
"router.deliver.ip_self").
write10((u32)meta.
src_port());
107 return deliver_local(meta);
108 }
else if (meta.
is_ip()) {
110 if (DEBUG_VERBOSE > 1)
Log(DEBUG,
"router.deliver.ip_from").
write10((u32)meta.
src_port());
111 return process_gateway(meta);
115 if (DEBUG_VERBOSE > 1)
Log(DEBUG,
"router.deliver.drop").
write10((u32)meta.
src_port());
122 if (!meta.
is_arp())
return 0;
129 bool ok = rd.read_obj(eth) && rd.read_obj(arp);
133 if (DEBUG_VERBOSE > 1)
Log(DEBUG,
"router.arp.tpa").
write(arp.
tpa);
134 if (!m_local_iface)
return 0;
136 if (DEBUG_VERBOSE > 0)
Log(DEBUG,
"router.arp_to").
write10((u32)route.port);
140 if (route.port == m_local_port.
port_index())
return 0;
147 if (DEBUG_VERBOSE > 0)
Log(DEBUG,
"router.defer").
write(meta.
ip.
dst());
148 return (m_defer_fwd && m_defer_fwd->
accept(meta)) ? 1 : 0;
151 unsigned Dispatch::deliver_local(
const PluginPacket& meta) {
159 unsigned Dispatch::deliver_offload(
const PluginPacket& meta) {
163 if (m_offload) m_offload->
deliver(meta);
167 unsigned Dispatch::process_gateway(
PluginPacket& meta) {
171 MultiPacket::Reader rd(meta.
pkt);
172 if (!rd.read_obj(meta.
hdr))
return 0;
173 if (!rd.read_obj(meta.
ip))
return 0;
174 if (DEBUG_VERBOSE > 1)
Log(DEBUG,
"router.gateway.start").
write(meta.
ip.
dst());
179 icmp_reply(satcat5::ip::ICMP_TTL_EXPIRED, 0, meta);
184 if (!m_local_iface)
return 0;
186 if (DEBUG_VERBOSE > 1)
Log(DEBUG,
"router.gateway.route\r\n ").
write_obj(route);
189 if(meta.
hdr.
dst != m_local_iface->macaddr()){
190 if (DEBUG_VERBOSE > 1)
Log(WARNING,
"Packet received at gateway with dest").
write(meta.
hdr.
dst);
200 if (!route.is_deliverable()) {
201 icmp_reply(satcat5::ip::ICMP_UNREACHABLE_NET, 0, meta);
204 icmp_reply(satcat5::ip::ICMP_NET_PROHIBITED, 0, meta);
211 icmp_reply(satcat5::ip::ICMP_UNREACHABLE_NET, 0, meta);
217 bool multi_offload = route.is_multicast() && is_from_offload(meta);
224 if (route.port == meta.
src_port()) {
225 icmp_reply(satcat5::ip::ICMP_REDIRECT_HOST, route.gateway.value, meta);
226 if (is_from_offload(meta))
return 0;
230 if (route.has_dstmac()) {
232 if (DEBUG_VERBOSE > 0)
Log(DEBUG,
"router.gateway.fwd_to").
write10((u32)route.port);
233 adjust_mac(route.dstmac, meta);
234 if (DEBUG_VERBOSE > 0 && m_debug) meta.
pkt->
copy_to(m_debug);
238 if (DEBUG_VERBOSE > 1)
Log(DEBUG,
"router.gateway.defer").
write10((u32)route.port);
239 return deliver_defer(meta);
246 u8*
const dptr = meta.
pkt->m_chunks.head()->m_data;
249 wr.write_obj(macaddr());
254 if (meta.
ip.
ttl() == 0)
return false;
258 unsigned ipttl = iphdr + 8;
259 unsigned ipchk = iphdr + 10;
264 u8*
const dptr = meta.
pkt->m_chunks.head()->m_data;
265 u8 incr = (dptr[ipchk+1] == 0xFF) ? 2 : 1;
274 static constexpr
unsigned ICMP_WORDS = 4;
275 static constexpr
unsigned ECHO_WORDS = satcat5::ip::ICMP_ECHO_BYTES / 2;
277 bool Dispatch::icmp_reply(u16 errtyp, u32 arg,
const PluginPacket& meta) {
280 u16 tx_icmp[ICMP_WORDS];
281 u16 tx_echo[ECHO_WORDS];
284 if (meta.
ip.
dst() == ipaddr())
return false;
287 if (meta.
ip.
frg())
return false;
291 if(meta.
hdr.
dst != m_local_iface->macaddr())
return false;
294 MultiPacket::Reader rd(meta.
pkt);
295 if (!rd.read_obj(rx_eth))
return false;
296 if (!rd.read_obj(rx_ip))
return false;
297 for (
unsigned a = 0 ; a < ECHO_WORDS ; ++a)
298 tx_echo[a] = rd.read_u16();
303 u16 chk_echo = checksum(ECHO_WORDS, tx_echo, rx_ip.
chk());
306 tx_icmp[2] = (u16)(arg >> 16);
307 tx_icmp[3] = (u16)(arg >> 0);
308 tx_icmp[1] = checksum(ICMP_WORDS, tx_icmp, chk_echo);
313 ->
open_write(m_local_iface->macaddr(), satcat5::eth::ETYPE_IPV4, rx_eth.
vtag);
314 if (!wr)
return false;
317 unsigned tx_bytes = 2*ICMP_WORDS + 4*rx_ip.
ihl() + 2*ECHO_WORDS;
318 tx_ip = m_local_iface->
next_header(satcat5::ip::PROTO_ICMP, rx_ip.
src(), tx_bytes);
322 for (
unsigned a = 0 ; a < ICMP_WORDS ; ++a)
323 wr->write_u16(tx_icmp[a]);
325 for (
unsigned a = 0 ; a < ECHO_WORDS ; ++a)
326 wr->write_u16(tx_echo[a]);
330 bool Dispatch::is_from_offload(
const PluginPacket& meta) {
338 if (m_offload) clr_mask(link_up, m_offload->
link_shdn_sw());
satcat5::io::Writeable * open_write(const satcat5::eth::MacAddr &dst, const satcat5::eth::MacType &type, satcat5::eth::VlanTag vtag=satcat5::eth::VTAG_NONE)
Send a frame to the designated Ethernet address/VLAN.
unsigned deliver_switch(const satcat5::eth::PluginPacket &pkt)
Internal event-handlers called from deliver(...).
satcat5::util::optional< unsigned > process_plugins(satcat5::eth::PluginPacket &pkt)
Internal event-handlers called from deliver(...).
void process_stats(const satcat5::eth::PluginPacket &pkt)
Internal event-handlers called from deliver(...).
void debug_log(const satcat5::io::MultiPacket *pkt, u8 reason, SATCAT5_PMASK_TYPE dst=0) const
If logging is enabled, record the outcome for this packet.
unsigned port_index() const
Port number for attachment to the parent SwitchCore.
bool accept(SATCAT5_PMASK_TYPE dst_mask, satcat5::io::MultiPacket *packet)
Accept delivery of a given packet?
Ephemeral Writeable interface for a simple array.
Abstract API for writing byte-streams and packets.
virtual bool write_finalize()
Mark end of frame and release temporary working data.
void write_obj(const T &obj)
Templated wrapper for any object with the following method: void write_to(satcat5::io::Writeable* wr)...
satcat5::ip::Route route_lookup(const satcat5::ip::Addr &dstaddr) const
Routing table shortcuts.
satcat5::ip::Header next_header(u8 protocol, const satcat5::ip::Addr &dst, unsigned inner_bytes, u8 ttl=SATCAT5_IP_TTL)
Create a basic IPv4 header with the specified information.
The Log class creates and formats one log message.
Log & write10(s32 val)
Print integer as a decimal value with no leading zeros.
Log & write_obj(const T &obj)
Templated wrapper for custom output formatting.
Log & write(const char *str)
Formatting methods for various data types.
bool accept(const satcat5::eth::PluginPacket &meta)
Accept this packet into the queue?
Packet-processing pipeline for the IPv4 router.
unsigned deliver(satcat5::io::MultiPacket *packet) override
Override the MultiBuffer::deliver() method.
bool decrement_ttl(satcat5::eth::PluginPacket &meta)
u32 reconfigure()
Reload router IP address and MAC address.
SATCAT5_PMASK_TYPE port_mask_all() const
Return a port-mask containing all connected ports.
void deliver(const satcat5::eth::PluginPacket &meta)
Deliver a given packet to the hardware queue.
SATCAT5_PMASK_TYPE link_shdn_sw()
Mask indicating software-defined ports in the shutdown state.
Diagnostic logging system for the Ethernet switch.
#define SATCAT5_PMASK_TYPE
Set the integer type used to identify source and destination ports.
constexpr SATCAT5_PMASK_TYPE idx2mask(unsigned idx)
Macro converting port-index to a bit-mask.
Internet Protocol v4 (IPv4) forwarding table.
Diagnostic logging to UART and/or Ethernet ports.
constexpr s8 WARNING
Define basic priority codes for log messages.
constexpr s8 DEBUG
Define basic priority codes for log messages.
An Ethernet MAC address (with serializable interface).
bool is_l2multicast() const
L2 multicast (01:80:C2:*:*:* except link-local)
bool is_swcontrol() const
Link-local control (01:80:C2:00:00:*)
bool is_multicast() const
Broadcast, L2 multicast, or L3 multicast.
u16 value
The 16-bit value is stored in processor-native order.
Ephemeral data structure provided to plugin callbacks.
satcat5::io::MultiPacket * pkt
Complete packet contents.
satcat5::ip::Header ip
Copy of additional header fields, if present.
bool is_ip() const
Accessors and shortcuts for packet metadata.
unsigned src_port() const
Accessors and shortcuts for packet metadata.
bool is_arp() const
Accessors and shortcuts for packet metadata.
SATCAT5_PMASK_TYPE dst_mask
Destination mask for which port(s) receive this packet.
SATCAT5_PMASK_TYPE src_mask() const
Accessors and shortcuts for packet metadata.
satcat5::eth::Header hdr
Copy of Ethernet header fields.
A single 24-byte packet-log message.
u16 value
The 16-bit value holds VID, DEI, and PCP fields.
A packet is a linked-list of memory blocks, plus metadata.
bool copy_to(satcat5::io::Writeable *wr) const
Copy the packet contents to the specified destination.
satcat5::io::ArrayRead peek() const
Peek at the first chunk, up to SATCAT5_MBUFF_CHUNK bytes.
IPv4 address is a 32-bit unsigned integer.
bool is_multicast() const
IP multicast (224.*.*.*)
bool is_reserved() const
Reserved blocks (0.*.*.* or 127.*.*.*)
Miscellaneous mathematical utility functions.
void clr_mask(T &val, T mask)
Set or clear bit masks.