39 #include <sys/types.h>
40 #include <sys/socket.h>
41 #include <linux/netlink.h>
42 #include <linux/rtnetlink.h>
44 #define SNDBUF_SIZE (1024 * 2)
45 #define RCVBUF_SIZE (1024 * 4)
47 #define SITNL_ADDATTR(_msg, _max_size, _attr, _data, _size) \
49 if (sitnl_addattr(_msg, _max_size, _attr, _data, _size) < 0) \
55 #define NLMSG_TAIL(nmsg) \
56 ((struct rtattr *)(((uint8_t *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
58 #define SITNL_NEST(_msg, _max_size, _attr) \
60 struct rtattr *_nest = NLMSG_TAIL(_msg); \
61 SITNL_ADDATTR(_msg, _max_size, _attr, NULL, 0); \
65 #define SITNL_NEST_END(_msg, _nest) \
67 _nest->rta_len = (void *)NLMSG_TAIL(_msg) - (void *)_nest; \
82 struct sitnl_link_req {
91 struct sitnl_addr_req {
100 struct sitnl_route_req {
106 typedef int (*sitnl_parse_reply_cb)(
struct nlmsghdr *
msg,
void *arg);
111 struct sitnl_route_data_cb {
120 sitnl_addattr(
struct nlmsghdr *n,
int maxlen,
int type,
const void *data,
123 int len = RTA_LENGTH(alen);
126 if ((
int)(NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len)) > maxlen)
128 msg(
M_WARN,
"%s: rtnl: message exceeded bound of %d", __func__,
134 rta->rta_type = type;
139 memset(RTA_DATA(rta), 0, alen);
143 memcpy(RTA_DATA(rta), data, alen);
146 n->nlmsg_len = NLMSG_ALIGN(n->nlmsg_len) + RTA_ALIGN(len);
157 int sndbuf = SNDBUF_SIZE;
158 int rcvbuf = RCVBUF_SIZE;
161 fd = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
164 msg(
M_WARN,
"%s: cannot open netlink socket", __func__);
168 if (setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sndbuf,
sizeof(sndbuf)) < 0)
175 if (setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &rcvbuf,
sizeof(rcvbuf)) < 0)
189 sitnl_bind(
int fd, uint32_t groups)
192 struct sockaddr_nl local;
196 local.nl_family = AF_NETLINK;
197 local.nl_groups = groups;
199 if (bind(fd, (
struct sockaddr *)&local,
sizeof(local)) < 0)
205 addr_len =
sizeof(local);
206 if (getsockname(fd, (
struct sockaddr *)&local, &addr_len) < 0)
212 if (addr_len !=
sizeof(local))
214 msg(
M_WARN,
"%s: wrong address length %d", __func__, addr_len);
218 if (local.nl_family != AF_NETLINK)
220 msg(
M_WARN,
"%s: wrong address family %d", __func__, local.nl_family);
231 sitnl_send(
struct nlmsghdr *payload, pid_t peer,
unsigned int groups,
232 sitnl_parse_reply_cb cb,
void *arg_cb)
234 int len, rem_len, fd, ret, rcv_len;
235 struct sockaddr_nl nladdr;
236 struct nlmsgerr *err;
243 .iov_len = payload->nlmsg_len,
245 struct msghdr nlmsg =
248 .msg_namelen =
sizeof(nladdr),
255 nladdr.nl_family = AF_NETLINK;
256 nladdr.nl_pid = peer;
257 nladdr.nl_groups = groups;
259 payload->nlmsg_seq = seq = time(NULL);
264 payload->nlmsg_flags |= NLM_F_ACK;
274 ret = sitnl_bind(fd, 0);
282 ret = sendmsg(fd, &nlmsg, 0);
291 memset(buf, 0,
sizeof(buf));
300 msg(
D_RTNL,
"%s: checking for received messages", __func__);
301 iov.iov_len =
sizeof(buf);
302 rcv_len = recvmsg(fd, &nlmsg, 0);
303 msg(
D_RTNL,
"%s: rtnl: received %d bytes", __func__, rcv_len);
306 if ((errno == EINTR) || (errno == EAGAIN))
308 msg(
D_RTNL,
"%s: interrupted call", __func__);
318 msg(
M_WARN,
"%s: rtnl: socket reached unexpected EOF", __func__);
323 if (nlmsg.msg_namelen !=
sizeof(nladdr))
325 msg(
M_WARN,
"%s: sender address length: %u (expected %zu)",
326 __func__, nlmsg.msg_namelen,
sizeof(nladdr));
331 h = (
struct nlmsghdr *)buf;
332 while (rcv_len >= (
int)
sizeof(*h))
335 rem_len = len -
sizeof(*h);
337 if ((rem_len < 0) || (len > rcv_len))
339 if (nlmsg.msg_flags & MSG_TRUNC)
341 msg(
M_WARN,
"%s: truncated message", __func__);
345 msg(
M_WARN,
"%s: malformed message: len=%d", __func__, len);
362 if (h->nlmsg_type == NLMSG_DONE)
368 if (h->nlmsg_type == NLMSG_ERROR)
370 err = (
struct nlmsgerr *)NLMSG_DATA(h);
371 if (rem_len < (
int)
sizeof(
struct nlmsgerr))
373 msg(
M_WARN,
"%s: ERROR truncated", __func__);
383 int r = cb(h, arg_cb);
392 msg(
M_WARN,
"%s: rtnl: generic error (%d): %s",
393 __func__, err->error, strerror(-err->error));
402 int r = cb(h, arg_cb);
411 msg(
M_WARN,
"%s: RTNL: unexpected reply", __func__);
414 rcv_len -= NLMSG_ALIGN(len);
415 h = (
struct nlmsghdr *)((
char *)h + NLMSG_ALIGN(len));
418 if (nlmsg.msg_flags & MSG_TRUNC)
420 msg(
M_WARN,
"%s: message truncated", __func__);
426 msg(
M_WARN,
"%s: rtnl: %d not parsed bytes", __func__, rcv_len);
440 char iface[IFNAMSIZ];
446 sitnl_route_save(
struct nlmsghdr *n,
void *arg)
448 route_res_t *res = arg;
449 struct rtmsg *r = NLMSG_DATA(n);
450 struct rtattr *rta = RTM_RTA(r);
451 int len = n->nlmsg_len - NLMSG_LENGTH(
sizeof(*r));
452 unsigned int table, ifindex = 0;
456 if (res->default_only && r->rtm_dst_len != 0)
462 table = r->rtm_table;
464 while (RTA_OK(rta, len))
466 switch (rta->rta_type)
470 ifindex = *(
unsigned int *)RTA_DATA(rta);
484 table = *(
unsigned int *)RTA_DATA(rta);
488 rta = RTA_NEXT(rta, len);
492 if (res->table && res->table != table)
497 if (!if_indextoname(ifindex, res->iface))
506 memcpy(&res->gw, gw, res->addr_size);
514 void *best_gw,
char *best_iface)
516 struct sitnl_route_req req;
526 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.r));
527 req.n.nlmsg_type = RTM_GETROUTE;
528 req.n.nlmsg_flags = NLM_F_REQUEST;
530 req.r.rtm_family = af_family;
535 res.addr_size =
sizeof(in_addr_t);
540 if (!dst || !dst->
ipv4)
542 req.n.nlmsg_flags |= NLM_F_DUMP;
543 res.default_only =
true;
544 res.table = RT_TABLE_MAIN;
548 req.r.rtm_dst_len = 32;
553 res.addr_size =
sizeof(
struct in6_addr);
555 req.r.rtm_dst_len = 128;
563 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_DST, dst, res.addr_size);
565 ret = sitnl_send(&req.n, 0, 0, sitnl_route_save, &res);
572 memcpy(best_gw, &res.gw, res.addr_size);
573 strncpy(best_iface, res.iface, IFNAMSIZ);
582 struct in6_addr *best_gw,
char *best_iface)
585 char buf[INET6_ADDRSTRLEN];
594 inet_ntop(AF_INET6, &dst_v6.
ipv6, buf,
sizeof(buf)));
596 ret = sitnl_route_best_gw(AF_INET6, &dst_v6, best_gw, best_iface);
602 msg(
D_ROUTE,
"%s result: via %s dev %s", __func__,
603 inet_ntop(AF_INET6, best_gw, buf,
sizeof(buf)), best_iface);
613 in_addr_t *best_gw,
char *best_iface)
616 char buf[INET_ADDRSTRLEN];
621 dst_v4.
ipv4 = htonl(*dst);
625 inet_ntop(AF_INET, &dst_v4.
ipv4, buf,
sizeof(buf)));
627 ret = sitnl_route_best_gw(AF_INET, &dst_v4, best_gw, best_iface);
633 msg(
D_ROUTE,
"%s result: via %s dev %s", __func__,
634 inet_ntop(AF_INET, best_gw, buf,
sizeof(buf)), best_iface);
637 *best_gw = ntohl(*best_gw);
645 struct sitnl_link_req req;
652 msg(
M_WARN,
"%s: passed NULL interface", __func__);
656 ifindex = if_nametoindex(
iface);
659 msg(
M_WARN,
"%s: rtnl: cannot get ifindex for %s: %s", __func__,
iface,
664 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
665 req.n.nlmsg_flags = NLM_F_REQUEST;
666 req.n.nlmsg_type = RTM_NEWLINK;
668 req.i.ifi_family = AF_PACKET;
669 req.i.ifi_index = ifindex;
670 req.i.ifi_change |= IFF_UP;
673 req.i.ifi_flags |= IFF_UP;
677 req.i.ifi_flags &= ~IFF_UP;
680 msg(
M_INFO,
"%s: set %s %s", __func__,
iface, up ?
"up" :
"down");
682 return sitnl_send(&req.n, 0, 0, NULL, NULL);
689 struct sitnl_link_req req;
690 int ifindex, ret = -1;
694 ifindex = if_nametoindex(
iface);
702 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
703 req.n.nlmsg_flags = NLM_F_REQUEST;
704 req.n.nlmsg_type = RTM_NEWLINK;
706 req.i.ifi_family = AF_PACKET;
707 req.i.ifi_index = ifindex;
709 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_MTU, &mtu, 4);
713 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
722 struct sitnl_link_req req;
723 int ifindex, ret = -1;
727 ifindex = if_nametoindex(
iface);
735 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
736 req.n.nlmsg_flags = NLM_F_REQUEST;
737 req.n.nlmsg_type = RTM_NEWLINK;
739 req.i.ifi_family = AF_PACKET;
740 req.i.ifi_index = ifindex;
747 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
753 sitnl_addr_set(
int cmd, uint32_t flags,
int ifindex,
sa_family_t af_family,
757 struct sitnl_addr_req req;
763 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
764 req.n.nlmsg_type = cmd;
765 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
767 req.i.ifa_index = ifindex;
768 req.i.ifa_family = af_family;
773 size =
sizeof(
struct in_addr);
777 size =
sizeof(
struct in6_addr);
781 msg(
M_WARN,
"%s: rtnl: unknown address family %d", __func__,
789 prefixlen = size * 8;
791 req.i.ifa_prefixlen = prefixlen;
795 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_ADDRESS, remote, size);
800 SITNL_ADDATTR(&req.n,
sizeof(req), IFA_LOCAL, local, size);
803 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
831 msg(
M_WARN,
"%s: passed NULL interface", __func__);
835 ifindex = if_nametoindex(
iface);
843 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex,
844 af_family, local, remote, 0);
865 msg(
M_WARN,
"%s: passed NULL interface", __func__);
869 ifindex = if_nametoindex(
iface);
876 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, local, NULL, 0);
880 sitnl_route_set(
int cmd, uint32_t flags,
int ifindex,
sa_family_t af_family,
881 const void *dst,
int prefixlen,
882 const void *gw,
enum rt_class_t table,
int metric,
883 enum rt_scope_t scope,
int protocol,
int type)
885 struct sitnl_route_req req;
893 size =
sizeof(in_addr_t);
897 size =
sizeof(
struct in6_addr);
904 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.r));
905 req.n.nlmsg_type = cmd;
906 req.n.nlmsg_flags = NLM_F_REQUEST | flags;
908 req.r.rtm_family = af_family;
909 req.r.rtm_scope = scope;
910 req.r.rtm_protocol = protocol;
911 req.r.rtm_type = type;
912 req.r.rtm_dst_len = prefixlen;
916 req.r.rtm_table = table;
920 req.r.rtm_table = RT_TABLE_UNSPEC;
921 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_TABLE, &table, 4);
926 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_DST, dst, size);
931 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_GATEWAY, gw, size);
936 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_OIF, &ifindex, 4);
941 SITNL_ADDATTR(&req.n,
sizeof(req), RTA_PRIORITY, &metric, 4);
944 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
967 msg(
M_WARN,
"%s: passed NULL interface", __func__);
971 ifindex = if_nametoindex(
iface);
979 return sitnl_addr_set(RTM_NEWADDR, NLM_F_CREATE | NLM_F_REPLACE, ifindex,
980 af_family, addr, NULL, prefixlen);
1001 msg(
M_WARN,
"%s: passed NULL interface", __func__);
1005 ifindex = if_nametoindex(
iface);
1013 return sitnl_addr_set(RTM_DELADDR, 0, ifindex, af_family, addr, NULL,
1019 const in_addr_t *addr,
int prefixlen)
1022 char buf[INET_ADDRSTRLEN];
1029 addr_v4.
ipv4 = htonl(*addr);
1031 msg(
M_INFO,
"%s: %s/%d dev %s", __func__,
1032 inet_ntop(AF_INET, &addr_v4.
ipv4, buf,
sizeof(buf)), prefixlen,
iface);
1034 return sitnl_addr_add(AF_INET,
iface, &addr_v4, prefixlen);
1039 const struct in6_addr *addr,
int prefixlen)
1042 char buf[INET6_ADDRSTRLEN];
1049 addr_v6.
ipv6 = *addr;
1051 msg(
M_INFO,
"%s: %s/%d dev %s", __func__,
1052 inet_ntop(AF_INET6, &addr_v6.
ipv6, buf,
sizeof(buf)), prefixlen,
iface);
1054 return sitnl_addr_add(AF_INET6,
iface, &addr_v6, prefixlen);
1059 const in_addr_t *addr,
int prefixlen)
1062 char buf[INET_ADDRSTRLEN];
1069 addr_v4.
ipv4 = htonl(*addr);
1072 inet_ntop(AF_INET, &addr_v4.
ipv4, buf,
sizeof(buf)),
iface);
1074 return sitnl_addr_del(AF_INET,
iface, &addr_v4, prefixlen);
1079 const struct in6_addr *addr,
int prefixlen)
1082 char buf[INET6_ADDRSTRLEN];
1089 addr_v6.
ipv6 = *addr;
1091 msg(
M_INFO,
"%s: %s/%d dev %s", __func__,
1092 inet_ntop(AF_INET6, &addr_v6.
ipv6, buf,
sizeof(buf)), prefixlen,
iface);
1094 return sitnl_addr_del(AF_INET6,
iface, &addr_v6, prefixlen);
1099 const in_addr_t *local,
const in_addr_t *remote)
1103 char buf1[INET_ADDRSTRLEN];
1104 char buf2[INET_ADDRSTRLEN];
1111 local_v4.
ipv4 = htonl(*local);
1115 remote_v4.
ipv4 = htonl(*remote);
1118 msg(
M_INFO,
"%s: %s peer %s dev %s", __func__,
1119 inet_ntop(AF_INET, &local_v4.
ipv4, buf1,
sizeof(buf1)),
1120 inet_ntop(AF_INET, &remote_v4.
ipv4, buf2,
sizeof(buf2)),
iface);
1122 return sitnl_addr_ptp_add(AF_INET,
iface, &local_v4, &remote_v4);
1127 const in_addr_t *local,
const in_addr_t *remote)
1130 char buf[INET6_ADDRSTRLEN];
1138 local_v4.
ipv4 = htonl(*local);
1141 inet_ntop(AF_INET, &local_v4.
ipv4, buf,
sizeof(buf)),
iface);
1143 return sitnl_addr_ptp_del(AF_INET,
iface, &local_v4);
1148 int prefixlen,
const void *gw, uint32_t table,
int metric)
1150 enum rt_scope_t scope = RT_SCOPE_UNIVERSE;
1155 ifindex = if_nametoindex(
iface);
1166 table = RT_TABLE_MAIN;
1171 scope = RT_SCOPE_LINK;
1174 return sitnl_route_set(RTM_NEWROUTE, NLM_F_CREATE, ifindex,
1175 af_family, dst, prefixlen, gw, table, metric, scope,
1176 RTPROT_BOOT, RTN_UNICAST);
1181 const in_addr_t *gw,
const char *
iface,
1182 uint32_t table,
int metric)
1184 in_addr_t *dst_ptr = NULL, *gw_ptr = NULL;
1185 in_addr_t dst_be = 0, gw_be = 0;
1186 char dst_str[INET_ADDRSTRLEN];
1187 char gw_str[INET_ADDRSTRLEN];
1191 dst_be = htonl(*dst);
1201 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1202 inet_ntop(AF_INET, &dst_be, dst_str,
sizeof(dst_str)),
1203 prefixlen, inet_ntop(AF_INET, &gw_be, gw_str,
sizeof(gw_str)),
1206 return sitnl_route_add(
iface, AF_INET, dst_ptr, prefixlen, gw_ptr, table,
1212 int prefixlen,
const struct in6_addr *gw,
1213 const char *
iface, uint32_t table,
int metric)
1217 char dst_str[INET6_ADDRSTRLEN];
1218 char gw_str[INET6_ADDRSTRLEN];
1230 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1231 inet_ntop(AF_INET6, &dst_v6.
ipv6, dst_str,
sizeof(dst_str)),
1232 prefixlen, inet_ntop(AF_INET6, &gw_v6.
ipv6, gw_str,
sizeof(gw_str)),
1235 return sitnl_route_add(
iface, AF_INET6, dst, prefixlen, gw, table,
1248 ifindex = if_nametoindex(
iface);
1259 table = RT_TABLE_MAIN;
1262 return sitnl_route_set(RTM_DELROUTE, 0, ifindex, af_family, dst, prefixlen,
1263 gw, table, metric, RT_SCOPE_NOWHERE, 0, 0);
1268 const in_addr_t *gw,
const char *
iface, uint32_t table,
1273 char dst_str[INET_ADDRSTRLEN];
1274 char gw_str[INET_ADDRSTRLEN];
1278 dst_v4.
ipv4 = htonl(*dst);
1283 gw_v4.
ipv4 = htonl(*gw);
1286 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1287 inet_ntop(AF_INET, &dst_v4.
ipv4, dst_str,
sizeof(dst_str)),
1288 prefixlen, inet_ntop(AF_INET, &gw_v4.
ipv4, gw_str,
sizeof(gw_str)),
1291 return sitnl_route_del(
iface, AF_INET, &dst_v4, prefixlen, &gw_v4, table,
1297 int prefixlen,
const struct in6_addr *gw,
1298 const char *
iface, uint32_t table,
int metric)
1302 char dst_str[INET6_ADDRSTRLEN];
1303 char gw_str[INET6_ADDRSTRLEN];
1315 msg(
D_ROUTE,
"%s: %s/%d via %s dev %s table %d metric %d", __func__,
1316 inet_ntop(AF_INET6, &dst_v6.
ipv6, dst_str,
sizeof(dst_str)),
1317 prefixlen, inet_ntop(AF_INET6, &gw_v6.
ipv6, gw_str,
sizeof(gw_str)),
1320 return sitnl_route_del(
iface, AF_INET6, &dst_v6, prefixlen, &gw_v6,
1329 struct sitnl_link_req req = { };
1334 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1335 req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
1336 req.n.nlmsg_type = RTM_NEWLINK;
1338 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_IFNAME,
iface, strlen(
iface) + 1);
1340 struct rtattr *linkinfo = SITNL_NEST(&req.n,
sizeof(req), IFLA_LINKINFO);
1341 SITNL_ADDATTR(&req.n,
sizeof(req), IFLA_INFO_KIND, type, strlen(type) + 1);
1342 #if defined(ENABLE_DCO)
1343 if (arg && (strcmp(type,
"ovpn-dco") == 0))
1346 struct rtattr *data = SITNL_NEST(&req.n,
sizeof(req), IFLA_INFO_DATA);
1349 SITNL_NEST_END(&req.n, data);
1352 SITNL_NEST_END(&req.n, linkinfo);
1354 req.i.ifi_family = AF_PACKET;
1358 ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
1364 sitnl_parse_rtattr_flags(
struct rtattr *tb[],
int max,
struct rtattr *rta,
1365 int len,
unsigned short flags)
1367 unsigned short type;
1369 memset(tb, 0,
sizeof(
struct rtattr *) * (max + 1));
1371 while (RTA_OK(rta, len))
1373 type = rta->rta_type & ~flags;
1375 if ((type <= max) && (!tb[type]))
1380 rta = RTA_NEXT(rta, len);
1385 msg(
D_ROUTE,
"%s: %d bytes not parsed! (rta_len=%d)", __func__, len,
1393 sitnl_parse_rtattr(
struct rtattr *tb[],
int max,
struct rtattr *rta,
int len)
1395 return sitnl_parse_rtattr_flags(tb, max, rta, len, 0);
1398 #define sitnl_parse_rtattr_nested(tb, max, rta) \
1399 (sitnl_parse_rtattr_flags(tb, max, RTA_DATA(rta), RTA_PAYLOAD(rta), \
1403 sitnl_type_save(
struct nlmsghdr *n,
void *arg)
1406 struct ifinfomsg *ifi = NLMSG_DATA(n);
1407 struct rtattr *tb[IFLA_MAX + 1];
1410 ret = sitnl_parse_rtattr(tb, IFLA_MAX, IFLA_RTA(ifi), IFLA_PAYLOAD(n));
1416 if (tb[IFLA_LINKINFO])
1418 struct rtattr *tb_link[IFLA_INFO_MAX + 1];
1420 ret = sitnl_parse_rtattr_nested(tb_link, IFLA_INFO_MAX,
1427 if (!tb_link[IFLA_INFO_KIND])
1442 struct sitnl_link_req req = { };
1443 int ifindex = if_nametoindex(
iface);
1450 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1451 req.n.nlmsg_flags = NLM_F_REQUEST;
1452 req.n.nlmsg_type = RTM_GETLINK;
1454 req.i.ifi_family = AF_PACKET;
1455 req.i.ifi_index = ifindex;
1459 int ret = sitnl_send(&req.n, 0, 0, sitnl_type_save, type);
1462 msg(
D_ROUTE,
"%s: cannot retrieve iface %s: %s (%d)", __func__,
iface,
1463 strerror(-ret), ret);
1475 struct sitnl_link_req req = { };
1476 int ifindex = if_nametoindex(
iface);
1483 req.n.nlmsg_len = NLMSG_LENGTH(
sizeof(req.i));
1484 req.n.nlmsg_flags = NLM_F_REQUEST;
1485 req.n.nlmsg_type = RTM_DELLINK;
1487 req.i.ifi_family = AF_PACKET;
1488 req.i.ifi_index = ifindex;
1492 return sitnl_send(&req.n, 0, 0, NULL, NULL);