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