1 // SPDX-License-Identifier: GPL-2.0
2 /* Original from tools/testing/selftests/net/ipsec.c */
3 #include <linux/netlink.h>
4 #include <linux/random.h>
5 #include <linux/rtnetlink.h>
6 #include <linux/veth.h>
10 #include <sys/socket.h>
14 #define MAX_PAYLOAD 2048
16 static int netlink_sock(int *sock
, uint32_t *seq_nr
, int proto
)
23 *sock
= socket(AF_NETLINK
, SOCK_RAW
| SOCK_CLOEXEC
, proto
);
25 test_print("socket(AF_NETLINK)");
29 randomize_buffer(seq_nr
, sizeof(*seq_nr
));
34 static int netlink_check_answer(int sock
, bool quite
)
39 struct nlmsghdr orig_msg
;
42 if (recv(sock
, &answer
, sizeof(answer
), 0) < 0) {
45 } else if (answer
.hdr
.nlmsg_type
!= NLMSG_ERROR
) {
46 test_print("expected NLMSG_ERROR, got %d",
47 (int)answer
.hdr
.nlmsg_type
);
49 } else if (answer
.error
) {
51 test_print("NLMSG_ERROR: %d: %s",
52 answer
.error
, strerror(-answer
.error
));
60 static inline struct rtattr
*rtattr_hdr(struct nlmsghdr
*nh
)
62 return (struct rtattr
*)((char *)(nh
) + RTA_ALIGN((nh
)->nlmsg_len
));
65 static int rtattr_pack(struct nlmsghdr
*nh
, size_t req_sz
,
66 unsigned short rta_type
, const void *payload
, size_t size
)
68 /* NLMSG_ALIGNTO == RTA_ALIGNTO, nlmsg_len already aligned */
69 struct rtattr
*attr
= rtattr_hdr(nh
);
70 size_t nl_size
= RTA_ALIGN(nh
->nlmsg_len
) + RTA_LENGTH(size
);
72 if (req_sz
< nl_size
) {
73 test_print("req buf is too small: %zu < %zu", req_sz
, nl_size
);
76 nh
->nlmsg_len
= nl_size
;
78 attr
->rta_len
= RTA_LENGTH(size
);
79 attr
->rta_type
= rta_type
;
80 memcpy(RTA_DATA(attr
), payload
, size
);
85 static struct rtattr
*_rtattr_begin(struct nlmsghdr
*nh
, size_t req_sz
,
86 unsigned short rta_type
, const void *payload
, size_t size
)
88 struct rtattr
*ret
= rtattr_hdr(nh
);
90 if (rtattr_pack(nh
, req_sz
, rta_type
, payload
, size
))
96 static inline struct rtattr
*rtattr_begin(struct nlmsghdr
*nh
, size_t req_sz
,
97 unsigned short rta_type
)
99 return _rtattr_begin(nh
, req_sz
, rta_type
, 0, 0);
102 static inline void rtattr_end(struct nlmsghdr
*nh
, struct rtattr
*attr
)
104 char *nlmsg_end
= (char *)nh
+ nh
->nlmsg_len
;
106 attr
->rta_len
= nlmsg_end
- (char *)attr
;
109 static int veth_pack_peerb(struct nlmsghdr
*nh
, size_t req_sz
,
110 const char *peer
, int ns
)
113 struct rtattr
*peer_attr
;
115 memset(&pi
, 0, sizeof(pi
));
116 pi
.ifi_family
= AF_UNSPEC
;
117 pi
.ifi_change
= 0xFFFFFFFF;
119 peer_attr
= _rtattr_begin(nh
, req_sz
, VETH_INFO_PEER
, &pi
, sizeof(pi
));
123 if (rtattr_pack(nh
, req_sz
, IFLA_IFNAME
, peer
, strlen(peer
)))
126 if (rtattr_pack(nh
, req_sz
, IFLA_NET_NS_FD
, &ns
, sizeof(ns
)))
129 rtattr_end(nh
, peer_attr
);
134 static int __add_veth(int sock
, uint32_t seq
, const char *name
,
137 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_EXCL
| NLM_F_CREATE
;
140 struct ifinfomsg info
;
141 char attrbuf
[MAX_PAYLOAD
];
143 static const char veth_type
[] = "veth";
144 struct rtattr
*link_info
, *info_data
;
146 memset(&req
, 0, sizeof(req
));
147 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(req
.info
));
148 req
.nh
.nlmsg_type
= RTM_NEWLINK
;
149 req
.nh
.nlmsg_flags
= flags
;
150 req
.nh
.nlmsg_seq
= seq
;
151 req
.info
.ifi_family
= AF_UNSPEC
;
152 req
.info
.ifi_change
= 0xFFFFFFFF;
154 if (rtattr_pack(&req
.nh
, sizeof(req
), IFLA_IFNAME
, name
, strlen(name
)))
157 if (rtattr_pack(&req
.nh
, sizeof(req
), IFLA_NET_NS_FD
, &ns_a
, sizeof(ns_a
)))
160 link_info
= rtattr_begin(&req
.nh
, sizeof(req
), IFLA_LINKINFO
);
164 if (rtattr_pack(&req
.nh
, sizeof(req
), IFLA_INFO_KIND
, veth_type
, sizeof(veth_type
)))
167 info_data
= rtattr_begin(&req
.nh
, sizeof(req
), IFLA_INFO_DATA
);
171 if (veth_pack_peerb(&req
.nh
, sizeof(req
), name
, ns_b
))
174 rtattr_end(&req
.nh
, info_data
);
175 rtattr_end(&req
.nh
, link_info
);
177 if (send(sock
, &req
, req
.nh
.nlmsg_len
, 0) < 0) {
178 test_print("send()");
181 return netlink_check_answer(sock
, false);
184 int add_veth(const char *name
, int nsfda
, int nsfdb
)
186 int route_sock
= -1, ret
;
189 if (netlink_sock(&route_sock
, &route_seq
, NETLINK_ROUTE
))
190 test_error("Failed to open netlink route socket\n");
192 ret
= __add_veth(route_sock
, route_seq
++, name
, nsfda
, nsfdb
);
197 static int __ip_addr_add(int sock
, uint32_t seq
, const char *intf
,
198 int family
, union tcp_addr addr
, uint8_t prefix
)
200 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_EXCL
| NLM_F_CREATE
;
203 struct ifaddrmsg info
;
204 char attrbuf
[MAX_PAYLOAD
];
206 size_t addr_len
= (family
== AF_INET
) ? sizeof(struct in_addr
) :
207 sizeof(struct in6_addr
);
209 memset(&req
, 0, sizeof(req
));
210 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(req
.info
));
211 req
.nh
.nlmsg_type
= RTM_NEWADDR
;
212 req
.nh
.nlmsg_flags
= flags
;
213 req
.nh
.nlmsg_seq
= seq
;
214 req
.info
.ifa_family
= family
;
215 req
.info
.ifa_prefixlen
= prefix
;
216 req
.info
.ifa_index
= if_nametoindex(intf
);
217 req
.info
.ifa_flags
= IFA_F_NODAD
;
219 if (rtattr_pack(&req
.nh
, sizeof(req
), IFA_LOCAL
, &addr
, addr_len
))
222 if (send(sock
, &req
, req
.nh
.nlmsg_len
, 0) < 0) {
223 test_print("send()");
226 return netlink_check_answer(sock
, true);
229 int ip_addr_add(const char *intf
, int family
,
230 union tcp_addr addr
, uint8_t prefix
)
232 int route_sock
= -1, ret
;
235 if (netlink_sock(&route_sock
, &route_seq
, NETLINK_ROUTE
))
236 test_error("Failed to open netlink route socket\n");
238 ret
= __ip_addr_add(route_sock
, route_seq
++, intf
,
239 family
, addr
, prefix
);
245 static int __ip_route_add(int sock
, uint32_t seq
, const char *intf
, int family
,
246 union tcp_addr src
, union tcp_addr dst
, uint8_t vrf
)
251 char attrbuf
[MAX_PAYLOAD
];
253 unsigned int index
= if_nametoindex(intf
);
254 size_t addr_len
= (family
== AF_INET
) ? sizeof(struct in_addr
) :
255 sizeof(struct in6_addr
);
257 memset(&req
, 0, sizeof(req
));
258 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(req
.rt
));
259 req
.nh
.nlmsg_type
= RTM_NEWROUTE
;
260 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_CREATE
;
261 req
.nh
.nlmsg_seq
= seq
;
262 req
.rt
.rtm_family
= family
;
263 req
.rt
.rtm_dst_len
= (family
== AF_INET
) ? 32 : 128;
264 req
.rt
.rtm_table
= vrf
;
265 req
.rt
.rtm_protocol
= RTPROT_BOOT
;
266 req
.rt
.rtm_scope
= RT_SCOPE_UNIVERSE
;
267 req
.rt
.rtm_type
= RTN_UNICAST
;
269 if (rtattr_pack(&req
.nh
, sizeof(req
), RTA_DST
, &dst
, addr_len
))
272 if (rtattr_pack(&req
.nh
, sizeof(req
), RTA_PREFSRC
, &src
, addr_len
))
275 if (rtattr_pack(&req
.nh
, sizeof(req
), RTA_OIF
, &index
, sizeof(index
)))
278 if (send(sock
, &req
, req
.nh
.nlmsg_len
, 0) < 0) {
279 test_print("send()");
283 return netlink_check_answer(sock
, true);
286 int ip_route_add_vrf(const char *intf
, int family
,
287 union tcp_addr src
, union tcp_addr dst
, uint8_t vrf
)
289 int route_sock
= -1, ret
;
292 if (netlink_sock(&route_sock
, &route_seq
, NETLINK_ROUTE
))
293 test_error("Failed to open netlink route socket\n");
295 ret
= __ip_route_add(route_sock
, route_seq
++, intf
,
296 family
, src
, dst
, vrf
);
302 int ip_route_add(const char *intf
, int family
,
303 union tcp_addr src
, union tcp_addr dst
)
305 return ip_route_add_vrf(intf
, family
, src
, dst
, RT_TABLE_MAIN
);
308 static int __link_set_up(int sock
, uint32_t seq
, const char *intf
)
312 struct ifinfomsg info
;
313 char attrbuf
[MAX_PAYLOAD
];
316 memset(&req
, 0, sizeof(req
));
317 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(req
.info
));
318 req
.nh
.nlmsg_type
= RTM_NEWLINK
;
319 req
.nh
.nlmsg_flags
= NLM_F_REQUEST
| NLM_F_ACK
;
320 req
.nh
.nlmsg_seq
= seq
;
321 req
.info
.ifi_family
= AF_UNSPEC
;
322 req
.info
.ifi_change
= 0xFFFFFFFF;
323 req
.info
.ifi_index
= if_nametoindex(intf
);
324 req
.info
.ifi_flags
= IFF_UP
;
325 req
.info
.ifi_change
= IFF_UP
;
327 if (send(sock
, &req
, req
.nh
.nlmsg_len
, 0) < 0) {
328 test_print("send()");
331 return netlink_check_answer(sock
, false);
334 int link_set_up(const char *intf
)
336 int route_sock
= -1, ret
;
339 if (netlink_sock(&route_sock
, &route_seq
, NETLINK_ROUTE
))
340 test_error("Failed to open netlink route socket\n");
342 ret
= __link_set_up(route_sock
, route_seq
++, intf
);
348 static int __add_vrf(int sock
, uint32_t seq
, const char *name
,
349 uint32_t tabid
, int ifindex
, int nsfd
)
351 uint16_t flags
= NLM_F_REQUEST
| NLM_F_ACK
| NLM_F_EXCL
| NLM_F_CREATE
;
354 struct ifinfomsg info
;
355 char attrbuf
[MAX_PAYLOAD
];
357 static const char vrf_type
[] = "vrf";
358 struct rtattr
*link_info
, *info_data
;
360 memset(&req
, 0, sizeof(req
));
361 req
.nh
.nlmsg_len
= NLMSG_LENGTH(sizeof(req
.info
));
362 req
.nh
.nlmsg_type
= RTM_NEWLINK
;
363 req
.nh
.nlmsg_flags
= flags
;
364 req
.nh
.nlmsg_seq
= seq
;
365 req
.info
.ifi_family
= AF_UNSPEC
;
366 req
.info
.ifi_change
= 0xFFFFFFFF;
367 req
.info
.ifi_index
= ifindex
;
369 if (rtattr_pack(&req
.nh
, sizeof(req
), IFLA_IFNAME
, name
, strlen(name
)))
373 if (rtattr_pack(&req
.nh
, sizeof(req
), IFLA_NET_NS_FD
,
374 &nsfd
, sizeof(nsfd
)))
377 link_info
= rtattr_begin(&req
.nh
, sizeof(req
), IFLA_LINKINFO
);
381 if (rtattr_pack(&req
.nh
, sizeof(req
), IFLA_INFO_KIND
, vrf_type
, sizeof(vrf_type
)))
384 info_data
= rtattr_begin(&req
.nh
, sizeof(req
), IFLA_INFO_DATA
);
388 if (rtattr_pack(&req
.nh
, sizeof(req
), IFLA_VRF_TABLE
,
389 &tabid
, sizeof(tabid
)))
392 rtattr_end(&req
.nh
, info_data
);
393 rtattr_end(&req
.nh
, link_info
);
395 if (send(sock
, &req
, req
.nh
.nlmsg_len
, 0) < 0) {
396 test_print("send()");
399 return netlink_check_answer(sock
, true);
402 int add_vrf(const char *name
, uint32_t tabid
, int ifindex
, int nsfd
)
404 int route_sock
= -1, ret
;
407 if (netlink_sock(&route_sock
, &route_seq
, NETLINK_ROUTE
))
408 test_error("Failed to open netlink route socket\n");
410 ret
= __add_vrf(route_sock
, route_seq
++, name
, tabid
, ifindex
, nsfd
);