xref: /linux/tools/testing/selftests/net/forwarding/ipmr.c (revision 91a4855d6c03e770e42f17c798a36a3c46e63de2)
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