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