| 1 | |
| 2 |
|
| 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 |
|
| 143 | .nlmsg_flags = NLM_F_REQUEST | NLM_F_ACK,
|
| 144 | .nlmsg_type = nlmsg_type,
|
| 145 | },
|
| 146 | .rtm = {
|
| 147 |
|
| 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;
|
| 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 |
|
| 278 | err = system("ip link del veth0");
|
| 279 | ASSERT_EQ(0, err);
|
| 280 |
|
| 281 |
|
| 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 |
|
| 299 | }
|
| 300 |
|
| 301 | TEST_F(ipmr, mrt_add_mfc)
|
| 302 | {
|
| 303 | int err;
|
| 304 |
|
| 305 |
|
| 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 |
|
| 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 |
|
| 400 | mfc_attr.ifindex = 0;
|
| 401 | err = nl_sendmsg_mfc(_metadata, self, variant, RTM_NEWROUTE, &mfc_attr);
|
| 402 | ASSERT_EQ(-ENFILE, err);
|
| 403 |
|
| 404 |
|
| 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 |
|
| 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 |
|
| 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 |
|
| 448 | err = system("ip link del veth0");
|
| 449 | ASSERT_EQ(0, err);
|
| 450 |
|
| 451 |
|
| 452 | err = system(variant->mfc_check_cmd);
|
| 453 | ASSERT_EQ(0, err);
|
| 454 |
|
| 455 | |
| 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 |
|
| 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 | |
| 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 |
|
| 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
|