#include <net/if.h>
#include <net/if_arp.h>
+#include <limits.h>
#include <arpa/inet.h>
#include <netinet/ether.h>
#include <netinet/in.h>
#include <linux/veth.h>
#include <linux/version.h>
+#include <sched.h>
+
#ifndef RTN_FAILED_POLICY
#define RTN_FAILED_POLICY 12
#endif
if (groups)
nl_join_groups(sock, groups);
- if (nl_connect(sock, protocol))
+ if (nl_connect(sock, protocol)) {
+ nl_socket_free(sock);
return NULL;
+ }
return sock;
}
struct clear_data *clr = arg;
struct nlmsghdr *hdr = nlmsg_hdr(msg);
bool (*cb)(struct nlmsghdr *, int ifindex);
- int type;
+ int type, ret;
switch(clr->type) {
case RTM_GETADDR:
D(SYSTEM, "Remove %s from device %s\n",
type == RTM_DELADDR ? "an address" : "a route",
clr->dev->ifname);
+
memcpy(nlmsg_hdr(clr->msg), hdr, hdr->nlmsg_len);
hdr = nlmsg_hdr(clr->msg);
hdr->nlmsg_type = type;
hdr->nlmsg_flags = NLM_F_REQUEST;
nl_socket_disable_auto_ack(sock_rtnl);
- nl_send_auto_complete(sock_rtnl, clr->msg);
+ ret = nl_send_auto_complete(sock_rtnl, clr->msg);
+ if (ret < 0) {
+ if (type == RTM_DELRULE)
+ D(SYSTEM, "Error deleting a rule: %d\n", ret);
+ else
+ D(SYSTEM, "Error deleting %s from device '%s': %d\n",
+ type == RTM_DELADDR ? "an address" : "a route",
+ clr->dev->ifname, ret);
+ }
+
nl_socket_enable_auto_ack(sock_rtnl);
return NL_SKIP;
system_if_clear_entries(struct device *dev, int type, int af)
{
struct clear_data clr;
- struct nl_cb *cb = nl_cb_alloc(NL_CB_DEFAULT);
+ struct nl_cb *cb;
struct rtmsg rtm = {
.rtm_family = af,
.rtm_flags = RTM_F_CLONED,
return;
}
+ cb = nl_cb_alloc(NL_CB_DEFAULT);
if (!cb)
return;
nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, cb_finish_event, &pending);
nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &pending);
- nl_send_auto_complete(sock_rtnl, clr.msg);
+ if (nl_send_auto_complete(sock_rtnl, clr.msg) < 0)
+ goto free;
+
while (pending > 0)
nl_recvmsgs(sock_rtnl, cb);
+free:
nlmsg_free(clr.msg);
out:
nl_cb_put(cb);
return -ENOMEM;
}
+int system_link_netns_move(const char *ifname, int netns_fd)
+{
+ struct nl_msg *msg;
+ struct ifinfomsg iim = {
+ .ifi_family = AF_UNSPEC,
+ .ifi_index = 0,
+ };
+
+ msg = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST);
+
+ if (!msg)
+ return -1;
+
+ nlmsg_append(msg, &iim, sizeof(iim), 0);
+ nla_put_string(msg, IFLA_IFNAME, ifname);
+ nla_put_u32(msg, IFLA_NET_NS_FD, netns_fd);
+ return system_rtnl_call(msg);
+}
+
static int system_link_del(const char *ifname)
{
struct nl_msg *msg;
return system_link_del(macvlan->ifname);
}
+int system_netns_open(const pid_t target_ns)
+{
+ char pid_net_path[PATH_MAX];
+
+ snprintf(pid_net_path, sizeof(pid_net_path), "/proc/%u/ns/net", target_ns);
+
+ return open(pid_net_path, O_RDONLY);
+}
+
+int system_netns_set(int netns_fd)
+{
+ return setns(netns_fd, CLONE_NEWNET);
+}
+
int system_veth_add(struct device *veth, struct veth_config *cfg)
{
struct nl_msg *msg;
nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, cb_if_check_ack, &chk);
nl_cb_err(cb, NL_CB_CUSTOM, cb_if_check_error, &chk);
- nl_send_auto_complete(sock_rtnl, msg);
+ ret = nl_send_auto_complete(sock_rtnl, msg);
+ if (ret < 0)
+ goto free;
+
while (chk.pending > 0)
nl_recvmsgs(sock_rtnl, cb);
};
struct nl_msg *msg;
- if (!dev)
- return 1;
-
if (cmd == RTM_NEWNEIGH)
flags |= NLM_F_CREATE | NLM_F_REPLACE;
int system_del_neighbor(struct device *dev, struct device_neighbor *neighbor)
{
- int rval = system_neigh(dev, neighbor, RTM_DELNEIGH);
- netifd_log_message(L_NOTICE,"return delete %d", rval);
- return rval;
+ return system_neigh(dev, neighbor, RTM_DELNEIGH);
}
static int system_rt(struct device *dev, struct device_route *route, int cmd)
struct timespec ts;
struct timeval tv;
- if (syscall(__NR_clock_gettime, CLOCK_MONOTONIC, &ts) == 0)
+ if (clock_gettime(CLOCK_MONOTONIC, &ts) == 0)
return ts.tv_sec;
if (gettimeofday(&tv, NULL) == 0)
}
#endif
+#ifdef IFLA_XFRM_MAX
+static int system_add_xfrm_tunnel(const char *name, const char *kind,
+ const unsigned int link, struct blob_attr **tb)
+{
+ struct nl_msg *nlm;
+ struct ifinfomsg ifi = { .ifi_family = AF_UNSPEC, };
+ struct blob_attr *cur;
+ int ret = 0;
+
+ nlm = nlmsg_alloc_simple(RTM_NEWLINK, NLM_F_REQUEST | NLM_F_REPLACE | NLM_F_CREATE);
+ if (!nlm)
+ return -1;
+
+ nlmsg_append(nlm, &ifi, sizeof(ifi), 0);
+ nla_put_string(nlm, IFLA_IFNAME, name);
+
+ struct nlattr *linkinfo = nla_nest_start(nlm, IFLA_LINKINFO);
+ if (!linkinfo) {
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ nla_put_string(nlm, IFLA_INFO_KIND, kind);
+ struct nlattr *infodata = nla_nest_start(nlm, IFLA_INFO_DATA);
+ if (!infodata) {
+ ret = -ENOMEM;
+ goto failure;
+ }
+
+ if (link)
+ nla_put_u32(nlm, IFLA_XFRM_LINK, link);
+
+ if ((cur = tb[TUNNEL_ATTR_DATA])) {
+ struct blob_attr *tb_data[__XFRM_DATA_ATTR_MAX];
+ uint32_t if_id = 0;
+
+ blobmsg_parse(xfrm_data_attr_list.params, __XFRM_DATA_ATTR_MAX, tb_data,
+ blobmsg_data(cur), blobmsg_len(cur));
+
+ if ((cur = tb_data[XFRM_DATA_IF_ID])) {
+ if ((if_id = blobmsg_get_u32(cur)))
+ nla_put_u32(nlm, IFLA_XFRM_IF_ID, if_id);
+ }
+
+ }
+
+ nla_nest_end(nlm, infodata);
+ nla_nest_end(nlm, linkinfo);
+
+ return system_rtnl_call(nlm);
+
+failure:
+ nlmsg_free(nlm);
+ return ret;
+}
+#endif
+
#ifdef IFLA_VXLAN_MAX
static int system_add_vxlan(const char *name, const unsigned int link, struct blob_attr **tb, bool v6)
{
if (!strcmp(str, "greip") || !strcmp(str, "gretapip") ||
!strcmp(str, "greip6") || !strcmp(str, "gretapip6") ||
!strcmp(str, "vtiip") || !strcmp(str, "vtiip6") ||
- !strcmp(str, "vxlan") || !strcmp(str, "vxlan6"))
+ !strcmp(str, "vxlan") || !strcmp(str, "vxlan6") ||
+ !strcmp(str, "xfrm"))
return system_link_del(name);
else
return tunnel_ioctl(name, SIOCDELTUNNEL, NULL);
} else if (!strcmp(str, "vtiip6")) {
return system_add_vti_tunnel(name, "vti6", link, tb, true);
#endif
+#ifdef IFLA_XFRM_MAX
+ } else if (!strcmp(str, "xfrm")) {
+ return system_add_xfrm_tunnel(name, "xfrm", link, tb);
+#endif
#ifdef IFLA_VXLAN_MAX
} else if(!strcmp(str, "vxlan")) {
return system_add_vxlan(name, link, tb, false);