Skip to content

Commit

Permalink
ip6: answer to router sollicit message
Browse files Browse the repository at this point in the history
Upon reception of a router sollicit message, trigger the existing
timer to send immediately a router advertismement packet.

Add relevant test: as the same mac address is defined for 2 interfaces
in the 2 namespaces, the same link local ip address will be generated
and used by linux.

Update github workflow and doc to reflect the addition of 'ndisc6'
as a test tool.

Signed-off-by: Christophe Fontaine <[email protected]>
  • Loading branch information
christophefontaine authored and rjarry committed Jan 17, 2025
1 parent 65aa832 commit 2e45b6c
Show file tree
Hide file tree
Showing 9 changed files with 331 additions and 172 deletions.
3 changes: 2 additions & 1 deletion .github/workflows/check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,8 @@ jobs:
sudo NEEDRESTART_MODE=l apt-get install -qy --no-install-recommends \
git socat tcpdump traceroute graphviz \
iproute2 iputils-ping libasan8 libedit2 \
libevent-2.1-7t64 libsmartcols1 libnuma1
libevent-2.1-7t64 libsmartcols1 libnuma1 \
ndisc6
- uses: actions/checkout@v4
with:
persist-credentials: false
Expand Down
19 changes: 15 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -237,17 +237,28 @@ image.
```sh
dnf install gcc git make meson ninja-build pkgconf scdoc python3-pyelftools \
libcmocka-devel libedit-devel libevent-devel numactl-devel \
libsmartcols-devel libarchive-devel rdma-core-devel \
clang-tools-extra jq curl traceroute graphviz
libsmartcols-devel libarchive-devel rdma-core-devel
```

or

```sh
apt install git gcc make meson ninja-build pkgconf scdoc python3-pyelftools \
libcmocka-dev libedit-dev libevent-dev libnuma-dev \
libsmartcols-dev libarchive-dev libibverbs-dev \
clang-format jq curl traceroute graphviz
libsmartcols-dev libarchive-dev libibverbs-dev
```

### Install optional dependencies
In order to run "make smoke-test" and "make update-graph", you'll need additional packages:

```sh
dnf install clang-tools-extra jq curl traceroute graphviz ndisc6
```

or

```sh
apt install clang-format jq curl traceroute graphviz ndisc6
```

### Build
Expand Down
352 changes: 185 additions & 167 deletions docs/graph.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions modules/ip6/control/gr_ip6_control.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ struct nexthop *ip6_nexthop_new(uint16_t vrf_id, uint16_t iface_id, const struct

void ip6_nexthop_unreachable_cb(struct rte_mbuf *m);
void ndp_probe_input_cb(struct rte_mbuf *m);
void ndp_router_sollicit_input_cb(struct rte_mbuf *m);

int ip6_route_insert(uint16_t vrf_id, uint16_t iface_id, const struct rte_ipv6_addr *, uint8_t prefixlen, struct nexthop *);
int ip6_route_delete(
Expand Down
5 changes: 5 additions & 0 deletions modules/ip6/control/router_advert.c
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,11 @@ static struct api_out iface_ra_clear(const void *request, void ** /*response*/)
return api_out(0, 0);
}

void ndp_router_sollicit_input_cb(struct rte_mbuf *m) {
rte_pktmbuf_free(m);
event_active(ra_ctx.timer, 0, 0);
}

static void build_ra_packet(struct rte_mbuf *m, struct rte_ipv6_addr *srcv6) {
struct rte_ipv6_addr dst = RTE_IPV6_ADDR_ALLNODES_LINK_LOCAL;
struct rte_ipv6_addr src = *srcv6;
Expand Down
5 changes: 5 additions & 0 deletions modules/ip6/datapath/icmp6_input.c
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2024 Robin Jarry

#include <gr_control_output.h>
#include <gr_datapath.h>
#include <gr_graph.h>
#include <gr_icmp6.h>
Expand All @@ -19,6 +20,7 @@ enum {
ICMP6_OUTPUT = 0,
NEIGH_SOLICIT,
NEIGH_ADVERT,
ROUTER_SOLICIT,
BAD_CHECKSUM,
INVALID,
UNSUPPORTED,
Expand Down Expand Up @@ -64,6 +66,8 @@ icmp6_input_process(struct rte_graph *graph, struct rte_node *node, void **objs,
next = NEIGH_ADVERT;
break;
case ICMP6_TYPE_ROUTER_SOLICIT:
next = ROUTER_SOLICIT;
break;
case ICMP6_TYPE_ROUTER_ADVERT:
default:
next = UNSUPPORTED;
Expand All @@ -89,6 +93,7 @@ static struct rte_node_register icmp6_input_node = {
[ICMP6_OUTPUT] = "icmp6_output",
[NEIGH_SOLICIT] = "ndp_ns_input",
[NEIGH_ADVERT] = "ndp_na_input",
[ROUTER_SOLICIT] = "ndp_rs_input",
[BAD_CHECKSUM] = "icmp6_input_bad_checksum",
[INVALID] = "icmp6_input_invalid",
[UNSUPPORTED] = "icmp6_input_unsupported",
Expand Down
1 change: 1 addition & 0 deletions modules/ip6/datapath/meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,6 @@ src += files(
'ndp_na_input.c',
'ndp_ns_input.c',
'ndp_ns_output.c',
'ndp_rs_input.c',
)
inc += include_directories('.')
92 changes: 92 additions & 0 deletions modules/ip6/datapath/ndp_rs_input.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
// SPDX-License-Identifier: BSD-3-Clause
// Copyright (c) 2025 Christophe Fontaine

#include <gr_control_output.h>
#include <gr_graph.h>
#include <gr_icmp6.h>
#include <gr_ip6_control.h>
#include <gr_ip6_datapath.h>
#include <gr_log.h>
#include <gr_mbuf.h>
#include <gr_trace.h>

#include <rte_byteorder.h>
#include <rte_ether.h>
#include <rte_graph_worker.h>
#include <rte_ip6.h>

enum {
CONTROL,
INVAL,
EDGE_COUNT,
};

static uint16_t ndp_rs_input_process(
struct rte_graph *graph,
struct rte_node *node,
void **objs,
uint16_t nb_objs
) {
struct control_output_mbuf_data *co;
struct ip6_local_mbuf_data *d;
struct rte_mbuf *mbuf;
struct icmp6 *icmp6;
rte_edge_t next;

#define ASSERT_NDP(condition) \
do { \
if (!(condition)) { \
next = INVAL; \
goto next; \
} \
} while (0)

for (uint16_t i = 0; i < nb_objs; i++) {
mbuf = objs[i];

d = ip6_local_mbuf_data(mbuf);
icmp6 = rte_pktmbuf_mtod(mbuf, struct icmp6 *);

// Validation of Router Solicitations
// https://www.rfc-editor.org/rfc/rfc4861#section-6.1.1
//
// - The IP Hop Limit field has a value of 255, i.e., the packet
// could not possibly have been forwarded by a router.
ASSERT_NDP(d->hop_limit == 255);
// - ICMP Checksum is valid. (already checked in icmp6_input)
//
// - ICMP Code is 0.
ASSERT_NDP(icmp6->code == 0);
// - ICMP length (derived from the IP length) is 8 or more octets.
ASSERT_NDP(d->len >= 8);

next = CONTROL;
co = control_output_mbuf_data(mbuf);
co->callback = ndp_router_sollicit_input_cb;
next:
if (gr_mbuf_is_traced(mbuf))
gr_mbuf_trace_add(mbuf, node, 0);
rte_node_enqueue_x1(graph, node, next, mbuf);
}

return nb_objs;
}

static struct rte_node_register node = {
.name = "ndp_rs_input",
.process = ndp_rs_input_process,
.nb_edges = EDGE_COUNT,
.next_nodes = {
[CONTROL] = "control_output",
[INVAL] = "ndp_rs_input_inval",
},
};

static struct gr_node_info info = {
.node = &node,
.trace_format = (gr_trace_format_cb_t)trace_icmp6_format,
};

GR_NODE_REGISTER(info);

GR_DROP_REGISTER(ndp_rs_input_inval);
25 changes: 25 additions & 0 deletions smoke/ip6_rs_ra_test.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#!/bin/bash
# SPDX-License-Identifier: BSD-3-Clause
# Copyright (c) 2025 Christophe Fontaine

. $(dirname $0)/_init.sh

p1=${run_id}1

grcli add interface port $p1 devargs net_tap0,iface=$p1 mac d2:f0:0c:ba:a4:11
grcli add ip6 address fd00:ba4:1::1/64 iface $p1

for n in 1; do
p=$run_id$n
ip netns add $p
echo ip netns del $p >> $tmp/cleanup
ip link set $p netns $p
ip -n $p link set $p address d2:ad:ca:ca:a4:1$n
ip -n $p link set $p up
ip -n $p addr add fd00:ba4:$n::2/64 dev $p
ip -n $p addr show
done

sleep 3 # wait for DAD

ip netns exec $p1 rdisc6 $p1

0 comments on commit 2e45b6c

Please sign in to comment.