diff --git a/modules/ip/datapath/gr_ip4_datapath.h b/modules/ip/datapath/gr_ip4_datapath.h index a0f242c3..e5355d94 100644 --- a/modules/ip/datapath/gr_ip4_datapath.h +++ b/modules/ip/datapath/gr_ip4_datapath.h @@ -4,6 +4,7 @@ #ifndef _GR_IP4_DATAPATH_H #define _GR_IP4_DATAPATH_H +#include #include #include #include @@ -14,7 +15,10 @@ #include -GR_MBUF_PRIV_DATA_TYPE(ip_output_mbuf_data, { struct nexthop *nh; }); +GR_MBUF_PRIV_DATA_TYPE(ip_output_mbuf_data, { + struct nexthop *nh; + const struct iface *input_iface; +}); GR_MBUF_PRIV_DATA_TYPE(arp_mbuf_data, { struct nexthop *local; @@ -50,4 +54,6 @@ static inline void ip_set_fields(struct rte_ipv4_hdr *ip, struct ip_local_mbuf_d ip->hdr_checksum = rte_ipv4_cksum(ip); } +#define GR_IP_ICMP_TTL_EXCEEDED 11 + #endif diff --git a/modules/ip/datapath/ip_forward.c b/modules/ip/datapath/ip_forward.c index 299fe0a8..3e67d77d 100644 --- a/modules/ip/datapath/ip_forward.c +++ b/modules/ip/datapath/ip_forward.c @@ -56,5 +56,3 @@ static struct gr_node_info info = { }; GR_NODE_REGISTER(info); - -GR_DROP_REGISTER(ip_forward_ttl_exceeded); diff --git a/modules/ip/datapath/ip_forward_ttl_exceeded.c b/modules/ip/datapath/ip_forward_ttl_exceeded.c new file mode 100644 index 00000000..a4f536e4 --- /dev/null +++ b/modules/ip/datapath/ip_forward_ttl_exceeded.c @@ -0,0 +1,81 @@ +// SPDX-License-Identifier: BSD-3-Clause +// Copyright (c) 2024 Christophe Fontaine + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +enum edges { + ICMP_OUTPUT = 0, + EDGE_COUNT, +}; + +static uint16_t ip_forward_ttl_exceeded( + struct rte_graph *graph, + struct rte_node *node, + void **objs, + uint16_t nb_objs +) { + struct ip_local_mbuf_data *ip_data; + const struct iface *input_iface; + struct rte_icmp_hdr *icmp; + struct rte_ipv4_hdr *ip; + struct rte_mbuf *mbuf; + uint16_t vrf_id; + + for (uint16_t i = 0; i < nb_objs; i++) { + mbuf = objs[i]; + + ip = rte_pktmbuf_mtod(mbuf, struct rte_ipv4_hdr *); + // No need to check headroom + icmp = (struct rte_icmp_hdr *) + rte_pktmbuf_prepend(mbuf, sizeof(struct rte_icmp_hdr)); + + // Get the local router IP address from the input iface + input_iface = ip_output_mbuf_data(mbuf)->input_iface; + vrf_id = input_iface->vrf_id; + ip4_addr_t local_ip = ip4_addr_get(input_iface->id)->ip; + + ip_data = ip_local_mbuf_data(mbuf); + ip_data->vrf_id = vrf_id; + ip_data->src = local_ip; + ip_data->dst = ip->src_addr; + + // RFC792 payload size: ip header + 64 bits of original datagram + ip_data->len = sizeof(struct rte_icmp_hdr) + rte_ipv4_hdr_len(ip) + 8; + ip_data->proto = IPPROTO_ICMP; + + icmp->icmp_type = GR_IP_ICMP_TTL_EXCEEDED; + icmp->icmp_code = 0; // time to live exceeded in transit + icmp->icmp_cksum = 0; + icmp->icmp_ident = 0; + icmp->icmp_seq_nb = 0; + + rte_node_enqueue_x1(graph, node, ICMP_OUTPUT, mbuf); + } + + return nb_objs; +} + +struct rte_node_register ip_forward_ttl_exceeded_node = { + .name = "ip_forward_ttl_exceeded", + .process = ip_forward_ttl_exceeded, + .nb_edges = EDGE_COUNT, + .next_nodes = { + [ICMP_OUTPUT] = "icmp_output", + }, +}; + +static struct gr_node_info info = { + .node = &ip_forward_ttl_exceeded_node, +}; + +GR_NODE_REGISTER(info); diff --git a/modules/ip/datapath/ip_input.c b/modules/ip/datapath/ip_input.c index 40b77f39..5eb3a5de 100644 --- a/modules/ip/datapath/ip_input.c +++ b/modules/ip/datapath/ip_input.c @@ -88,6 +88,7 @@ ip_input_process(struct rte_graph *graph, struct rte_node *node, void **objs, ui next = FORWARD; // Store the resolved next hop for ip_output to avoid a second route lookup. ip_output_mbuf_data(mbuf)->nh = nh; + ip_output_mbuf_data(mbuf)->input_iface = iface; next_packet: rte_node_enqueue_x1(graph, node, next, mbuf); } diff --git a/modules/ip/datapath/meson.build b/modules/ip/datapath/meson.build index 5cdaddc1..3b91e337 100644 --- a/modules/ip/datapath/meson.build +++ b/modules/ip/datapath/meson.build @@ -8,6 +8,7 @@ src += files( 'icmp_input.c', 'icmp_output.c', 'ip_forward.c', + 'ip_forward_ttl_exceeded.c', 'ip_input.c', 'ip_local.c', 'ip_output.c',