xref: /linux/tools/testing/selftests/net/forwarding/ipmr.c (revision 9415471e01c1aaac43daa6af3a261dc0c6c3a47c)
1 // SPDX-License-Identifier: GPL-2.0
2 /* Copyright 2026 Google LLC */
3 
4 #include <linux/if.h>
5 #include <linux/in6.h>
6 #include <linux/mroute.h>
7 #include <linux/mroute6.h>
8 #include <linux/netlink.h>
9 #include <linux/rtnetlink.h>
10 #include <linux/socket.h>
11 #include <sched.h>
12 #include <sys/ioctl.h>
13 #include <sys/socket.h>
14 
15 #include "kselftest_harness.h"
16 
17 FIXTURE(ipmr)
18 {
19 	int netlink_sk;
20 	int raw_sk;
21 	int veth_ifindex;
22 	union {
23 		struct vifctl vif;
24 		struct mif6ctl vif6;
25 	};
26 	union {
27 		struct mfcctl mfc;
28 		struct mf6cctl mfc6;
29 	};
30 };
31 
32 FIXTURE_VARIANT(ipmr)
33 {
34 	int family;
35 	int protocol;
36 	int level;
37 	int rtm_family;
38 	int opts[MRT_MAX - MRT_BASE + 1];
39 	int flush_flags;
40 	int vif_size;
41 	char vif_check_cmd_pimreg[64];
42 	char vif_check_cmd_veth[64];
43 	int mfc_size;
44 	char mfc_check_cmd[1024];
45 };
46 
47 FIXTURE_VARIANT_ADD(ipmr, ipv4)
48 {
49 	.family = AF_INET,
50 	.protocol = IPPROTO_IGMP,
51 	.level = IPPROTO_IP,
52 	.rtm_family = RTNL_FAMILY_IPMR,
53 	.opts = {
54 		MRT_INIT,
55 		MRT_DONE,
56 		MRT_ADD_VIF,
57 		MRT_DEL_VIF,
58 		MRT_ADD_MFC,
59 		MRT_DEL_MFC,
60 		MRT_VERSION,
61 		MRT_ASSERT,
62 		MRT_PIM,
63 		MRT_TABLE,
64 		MRT_ADD_MFC_PROXY,
65 		MRT_DEL_MFC_PROXY,
66 		MRT_FLUSH,
67 	},
68 	.flush_flags = MRT_FLUSH_MFC | MRT_FLUSH_MFC_STATIC |
69 		MRT_FLUSH_VIFS | MRT_FLUSH_VIFS_STATIC,
70 	.vif_size = sizeof(struct vifctl),
71 	.vif_check_cmd_pimreg = "cat /proc/net/ip_mr_vif | grep -q pimreg",
72 	.vif_check_cmd_veth = "cat /proc/net/ip_mr_vif | grep -q veth",
73 	.mfc_size = sizeof(struct mfcctl),
74 	.mfc_check_cmd = "cat /proc/net/ip_mr_cache | grep -q '00000000 00000000'",
75 };
76 
77 FIXTURE_VARIANT_ADD(ipmr, ipv6)
78 {
79 	.family = AF_INET6,
80 	.protocol = IPPROTO_ICMPV6,
81 	.level = IPPROTO_IPV6,
82 	.rtm_family = RTNL_FAMILY_IP6MR,
83 	.opts = {
84 		MRT6_INIT,
85 		MRT6_DONE,
86 		MRT6_ADD_MIF,
87 		MRT6_DEL_MIF,
88 		MRT6_ADD_MFC,
89 		MRT6_DEL_MFC,
90 		MRT6_VERSION,
91 		MRT6_ASSERT,
92 		MRT6_PIM,
93 		MRT6_TABLE,
94 		MRT6_ADD_MFC_PROXY,
95 		MRT6_DEL_MFC_PROXY,
96 		MRT6_FLUSH,
97 	},
98 	.flush_flags = MRT6_FLUSH_MFC | MRT6_FLUSH_MFC_STATIC |
99 		MRT6_FLUSH_MIFS | MRT6_FLUSH_MIFS_STATIC,
100 	.vif_size = sizeof(struct mif6ctl),
101 	.vif_check_cmd_pimreg = "cat /proc/net/ip6_mr_vif | grep -q pim6reg",
102 	.vif_check_cmd_veth = "cat /proc/net/ip6_mr_vif | grep -q veth",
103 	.mfc_size = sizeof(struct mf6cctl),
104 	.mfc_check_cmd = "cat /proc/net/ip6_mr_cache | "
105 		"grep -q '0000:0000:0000:0000:0000:0000:0000:0000 0000:0000:0000:0000:0000:0000:0000:0000'",
106 };
107 
108 struct mfc_attr {
109 	int table;
110 	__u32 origin;
111 	__u32 group;
112 	int ifindex;
113 	bool proxy;
114 };
115 
116 static struct rtattr *nl_add_rtattr(struct nlmsghdr *nlmsg, struct rtattr *rta,
117 				    int type, const void *data, int len)
118 {
119 	int unused = 0;
120 
121 	rta->rta_type = type;
122 	rta->rta_len = RTA_LENGTH(len);
123 	memcpy(RTA_DATA(rta), data, len);
124 
125 	nlmsg->nlmsg_len += NLMSG_ALIGN(rta->rta_len);
126 
127 	return RTA_NEXT(rta, unused);
128 }
129 
130 static int nl_sendmsg_mfc(struct __test_metadata *_metadata,
131 			  FIXTURE_DATA(ipmr) *self,
132 			  const FIXTURE_VARIANT(ipmr) *variant,
133 			  __u16 nlmsg_type, struct mfc_attr *mfc_attr)
134 {
135 	struct {
136 		struct nlmsghdr nlmsg;
137 		struct rtmsg rtm;
138 		char buf[4096];
139 	} req = {
140 		.nlmsg = {
141 			.nlmsg_len = NLMSG_LENGTH(sizeof(req.rtm)),
142 			/* ipmr does not care about NLM_F_CREATE and NLM_F_EXCL ... */
143 			.nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
144 			.nlmsg_type = nlmsg_type,
145 		},
146 		.rtm = {
147 			/* hard requirements in rtm_to_ipmr_mfcc() */
148 			.rtm_family = variant->rtm_family,
149 			.rtm_dst_len = 32,
150 			.rtm_type = RTN_MULTICAST,
151 			.rtm_scope = RT_SCOPE_UNIVERSE,
152 			.rtm_protocol = RTPROT_MROUTED,
153 		},
154 	};
155 	struct nlmsghdr *nlmsg = &req.nlmsg;
156 	struct nlmsgerr *errmsg;
157 	struct rtattr *rta;
158 	int err;
159 
160 	rta = (struct rtattr *)&req.buf;
161 	rta = nl_add_rtattr(nlmsg, rta, RTA_TABLE, &mfc_attr->table, sizeof(mfc_attr->table));
162 	rta = nl_add_rtattr(nlmsg, rta, RTA_SRC, &mfc_attr->origin, sizeof(mfc_attr->origin));
163 	rta = nl_add_rtattr(nlmsg, rta, RTA_DST, &mfc_attr->group, sizeof(mfc_attr->group));
164 	if (mfc_attr->ifindex)
165 		rta = nl_add_rtattr(nlmsg, rta, RTA_IIF, &mfc_attr->ifindex, sizeof(mfc_attr->ifindex));
166 	if (mfc_attr->proxy)
167 		rta = nl_add_rtattr(nlmsg, rta, RTA_PREFSRC, NULL, 0);
168 
169 	err = send(self->netlink_sk, &req, req.nlmsg.nlmsg_len, 0);
170 	ASSERT_EQ(err, req.nlmsg.nlmsg_len);
171 
172 	memset(&req, 0, sizeof(req));
173 
174 	err = recv(self->netlink_sk, &req, sizeof(req), 0);
175 	ASSERT_TRUE(NLMSG_OK(nlmsg, err));
176 	ASSERT_EQ(NLMSG_ERROR, nlmsg->nlmsg_type);
177 
178 	errmsg = (struct nlmsgerr *)NLMSG_DATA(nlmsg);
179 	return errmsg->error;
180 }
181 
182 FIXTURE_SETUP(ipmr)
183 {
184 	struct ifreq ifr = {
185 		.ifr_name = "veth0",
186 	};
187 	int err;
188 
189 	err = unshare(CLONE_NEWNET);
190 	ASSERT_EQ(0, err);
191 
192 	self->netlink_sk = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
193 	ASSERT_LE(0, self->netlink_sk);
194 
195 	self->raw_sk = socket(variant->family, SOCK_RAW, variant->protocol);
196 	ASSERT_LT(0, self->raw_sk);
197 
198 	err = system("ip link add veth0 type veth peer veth1");
199 	ASSERT_EQ(0, err);
200 
201 	err = ioctl(self->raw_sk, SIOCGIFINDEX, &ifr);
202 	ASSERT_EQ(0, err);
203 
204 	self->veth_ifindex = ifr.ifr_ifindex;
205 
206 	if (variant->family == AF_INET) {
207 		self->vif = (struct vifctl){
208 			.vifc_flags = VIFF_USE_IFINDEX,
209 			.vifc_lcl_ifindex = self->veth_ifindex,
210 		};
211 	} else {
212 		self->vif6 = (struct mif6ctl){
213 			.mif6c_flags = 0,
214 			.mif6c_pifi = self->veth_ifindex,
215 		};
216 	}
217 }
218 
219 FIXTURE_TEARDOWN(ipmr)
220 {
221 	close(self->raw_sk);
222 	close(self->netlink_sk);
223 }
224 
225 TEST_F(ipmr, mrt_init)
226 {
227 	int err, val = 0;  /* any value is ok, but size must be int for MRT_INIT. */
228 
229 	err = setsockopt(self->raw_sk,
230 			 variant->level, variant->opts[MRT_INIT - MRT_BASE],
231 			 &val,  sizeof(val));
232 	ASSERT_EQ(0, err);
233 
234 	err = setsockopt(self->raw_sk,
235 			 variant->level, variant->opts[MRT_DONE - MRT_BASE],
236 			 &val,  sizeof(val));
237 	ASSERT_EQ(0, err);
238 }
239 
240 TEST_F(ipmr, mrt_add_vif_register)
241 {
242 	int err;
243 
244 	memset(&self->vif, 0, variant->vif_size);
245 
246 	if (variant->family == AF_INET)
247 		self->vif.vifc_flags = VIFF_REGISTER;
248 	else
249 		self->vif6.mif6c_flags = MIFF_REGISTER;
250 
251 	err = setsockopt(self->raw_sk,
252 			 variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
253 			 &self->vif,  variant->vif_size);
254 	ASSERT_EQ(0, err);
255 
256 	err = system(variant->vif_check_cmd_pimreg);
257 	ASSERT_EQ(0, err);
258 
259 	err = setsockopt(self->raw_sk,
260 			 variant->level, variant->opts[MRT_DEL_VIF - MRT_BASE],
261 			 &self->vif,  variant->vif_size);
262 	ASSERT_EQ(0, err);
263 }
264 
265 TEST_F(ipmr, mrt_del_vif_unreg)
266 {
267 	int err;
268 
269 	err = setsockopt(self->raw_sk,
270 			 variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
271 			 &self->vif,  variant->vif_size);
272 	ASSERT_EQ(0, err);
273 
274 	err = system(variant->vif_check_cmd_veth);
275 	ASSERT_EQ(0, err);
276 
277 	/* VIF is removed along with its device. */
278 	err = system("ip link del veth0");
279 	ASSERT_EQ(0, err);
280 
281 	/* mrt->vif_table[veth_ifindex]->dev is NULL. */
282 	err = setsockopt(self->raw_sk,
283 			 variant->level, variant->opts[MRT_DEL_VIF - MRT_BASE],
284 			 &self->vif,  variant->vif_size);
285 	ASSERT_EQ(-1, err);
286 	ASSERT_EQ(EADDRNOTAVAIL, errno);
287 }
288 
289 TEST_F(ipmr, mrt_del_vif_netns_dismantle)
290 {
291 	int err;
292 
293 	err = setsockopt(self->raw_sk,
294 			 variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
295 			 &self->vif,  variant->vif_size);
296 	ASSERT_EQ(0, err);
297 
298 	/* Let cleanup_net() remove veth0 and VIF. */
299 }
300 
301 TEST_F(ipmr, mrt_add_mfc)
302 {
303 	int err;
304 
305 	/* MRT_ADD_MFC / MRT_ADD_MFC_PROXY does not need vif to exist (unlike netlink). */
306 	err = setsockopt(self->raw_sk,
307 			 variant->level, variant->opts[MRT_ADD_MFC - MRT_BASE],
308 			 &self->mfc, variant->mfc_size);
309 	ASSERT_EQ(0, err);
310 
311 	/* (0.0.0.0 -> 0.0.0.0) */
312 	err = system(variant->mfc_check_cmd);
313 	ASSERT_EQ(0, err);
314 
315 	err = setsockopt(self->raw_sk,
316 			 variant->level, variant->opts[MRT_DEL_MFC - MRT_BASE],
317 			 &self->mfc, variant->mfc_size);
318 }
319 
320 TEST_F(ipmr, mrt_add_mfc_proxy)
321 {
322 	int err;
323 
324 	err = setsockopt(self->raw_sk,
325 			 variant->level, variant->opts[MRT_ADD_MFC_PROXY - MRT_BASE],
326 			 &self->mfc, variant->mfc_size);
327 	ASSERT_EQ(0, err);
328 
329 	err = system(variant->mfc_check_cmd);
330 	ASSERT_EQ(0, err);
331 
332 	err = setsockopt(self->raw_sk,
333 			 variant->level, variant->opts[MRT_DEL_MFC_PROXY - MRT_BASE],
334 			 &self->mfc, variant->mfc_size);
335 }
336 
337 TEST_F(ipmr, mrt_add_mfc_netlink)
338 {
339 	struct mfc_attr mfc_attr = {
340 		.table = RT_TABLE_DEFAULT,
341 		.origin = 0,
342 		.group = 0,
343 		.ifindex = self->veth_ifindex,
344 		.proxy = false,
345 	};
346 	int err;
347 
348 	err = setsockopt(self->raw_sk,
349 			 variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
350 			 &self->vif, variant->vif_size);
351 	ASSERT_EQ(0, err);
352 
353 	err = nl_sendmsg_mfc(_metadata, self, variant, RTM_NEWROUTE, &mfc_attr);
354 	ASSERT_EQ(0, err);
355 
356 	err = system(variant->mfc_check_cmd);
357 	ASSERT_EQ(0, err);
358 
359 	err = nl_sendmsg_mfc(_metadata, self, variant, RTM_DELROUTE, &mfc_attr);
360 	ASSERT_EQ(0, err);
361 }
362 
363 TEST_F(ipmr, mrt_add_mfc_netlink_proxy)
364 {
365 	struct mfc_attr mfc_attr = {
366 		.table = RT_TABLE_DEFAULT,
367 		.origin = 0,
368 		.group = 0,
369 		.ifindex = self->veth_ifindex,
370 		.proxy = true,
371 	};
372 	int err;
373 
374 	err = setsockopt(self->raw_sk,
375 			 variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
376 			 &self->vif, variant->vif_size);
377 	ASSERT_EQ(0, err);
378 
379 	err = nl_sendmsg_mfc(_metadata, self, variant, RTM_NEWROUTE, &mfc_attr);
380 	ASSERT_EQ(0, err);
381 
382 	err = system(variant->mfc_check_cmd);
383 	ASSERT_EQ(0, err);
384 
385 	err = nl_sendmsg_mfc(_metadata, self, variant, RTM_DELROUTE, &mfc_attr);
386 	ASSERT_EQ(0, err);
387 }
388 
389 TEST_F(ipmr, mrt_add_mfc_netlink_no_vif)
390 {
391 	struct mfc_attr mfc_attr = {
392 		.table = RT_TABLE_DEFAULT,
393 		.origin = 0,
394 		.group = 0,
395 		.proxy = false,
396 	};
397 	int err;
398 
399 	/* netlink always requires RTA_IIF of an existing vif. */
400 	mfc_attr.ifindex = 0;
401 	err = nl_sendmsg_mfc(_metadata, self, variant, RTM_NEWROUTE, &mfc_attr);
402 	ASSERT_EQ(-ENFILE, err);
403 
404 	/* netlink always requires RTA_IIF of an existing vif. */
405 	mfc_attr.ifindex = self->veth_ifindex;
406 	err = nl_sendmsg_mfc(_metadata, self, variant, RTM_NEWROUTE, &mfc_attr);
407 	ASSERT_EQ(-ENFILE, err);
408 }
409 
410 TEST_F(ipmr, mrt_del_mfc_netlink_netns_dismantle)
411 {
412 	struct vifctl vifs[2] = {
413 		{
414 			.vifc_vifi = 0,
415 			.vifc_flags = VIFF_USE_IFINDEX,
416 			.vifc_lcl_ifindex = self->veth_ifindex,
417 		},
418 		{
419 			.vifc_vifi = 1,
420 			.vifc_flags = VIFF_REGISTER,
421 		}
422 	};
423 	struct mfc_attr mfc_attr = {
424 		.table = RT_TABLE_DEFAULT,
425 		.origin = 0,
426 		.group = 0,
427 		.ifindex = self->veth_ifindex,
428 		.proxy = false,
429 	};
430 	int i, err;
431 
432 	for (i = 0; i < 2; i++) {
433 		/* Create 2 VIFs just to avoid -ENFILE later. */
434 		err = setsockopt(self->raw_sk,
435 				 variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
436 				 &vifs[i],  sizeof(vifs[i]));
437 		ASSERT_EQ(0, err);
438 	}
439 
440 	/* Create a MFC for mrt->vif_table[0]. */
441 	err = nl_sendmsg_mfc(_metadata, self, variant, RTM_NEWROUTE, &mfc_attr);
442 	ASSERT_EQ(0, err);
443 
444 	err = system(variant->mfc_check_cmd);
445 	ASSERT_EQ(0, err);
446 
447 	/* Remove mrt->vif_table[0]. */
448 	err = system("ip link del veth0");
449 	ASSERT_EQ(0, err);
450 
451 	/* MFC entry is NOT removed even if the tied VIF is removed... */
452 	err = system(variant->mfc_check_cmd);
453 	ASSERT_EQ(0, err);
454 
455 	/* ... and netlink is not capable of removing such an entry
456 	 * because netlink always requires a valid RTA_IIF ... :/
457 	 */
458 	err = nl_sendmsg_mfc(_metadata, self, variant, RTM_DELROUTE, &mfc_attr);
459 	ASSERT_EQ(-ENODEV, err);
460 
461 	/* It can be removed by setsockopt(), but let cleanup_net() remove this time. */
462 }
463 
464 TEST_F(ipmr, mrt_table_flush)
465 {
466 	struct mfc_attr mfc_attr = {
467 		.origin = 0,
468 		.group = 0,
469 		.ifindex = self->veth_ifindex,
470 		.proxy = false,
471 	};
472 	int table_id = 92;
473 	int err;
474 
475 	/* Set a random table id rather than RT_TABLE_DEFAULT.
476 	 * Note that /proc/net/ip_mr_{vif,cache} only supports RT_TABLE_DEFAULT.
477 	 */
478 	err = setsockopt(self->raw_sk,
479 			 variant->level, variant->opts[MRT_TABLE - MRT_BASE],
480 			 &table_id,  sizeof(table_id));
481 	ASSERT_EQ(0, err);
482 
483 	err = setsockopt(self->raw_sk,
484 			 variant->level, variant->opts[MRT_ADD_VIF - MRT_BASE],
485 			 &self->vif,  variant->vif_size);
486 	ASSERT_EQ(0, err);
487 
488 	if (variant->family == AF_INET) {
489 		mfc_attr.table = table_id;
490 		err = nl_sendmsg_mfc(_metadata, self, variant, RTM_NEWROUTE, &mfc_attr);
491 	} else {
492 		err = setsockopt(self->raw_sk,
493 				 variant->level, variant->opts[MRT_ADD_MFC - MRT_BASE],
494 				 &self->mfc, variant->mfc_size);
495 	}
496 	ASSERT_EQ(0, err);
497 
498 	/* Flush mrt->vif_table[] and all caches. */
499 	err = setsockopt(self->raw_sk,
500 			 variant->level, variant->opts[MRT_FLUSH - MRT_BASE],
501 			 &variant->flush_flags,  sizeof(variant->flush_flags));
502 	ASSERT_EQ(0, err);
503 }
504 
505 XFAIL_ADD(ipmr, ipv6, mrt_add_mfc_netlink);
506 XFAIL_ADD(ipmr, ipv6, mrt_add_mfc_netlink_proxy);
507 XFAIL_ADD(ipmr, ipv6, mrt_add_mfc_netlink_no_vif);
508 XFAIL_ADD(ipmr, ipv6, mrt_del_mfc_netlink_netns_dismantle);
509 
510 TEST_HARNESS_MAIN
511