@@ -87,6 +87,27 @@ void net_ctx_reset(openvpn_net_ctx_t *ctx);
*/
void net_ctx_free(openvpn_net_ctx_t *ctx);
+/**
+ * Add a new interface
+ *
+ * @param ctx the implementation specific context
+ * @param iface interface to create
+ * @param type string describing interface type
+ * @param arg extra data required by the specific type
+ * @return int 0 on success, negative error code on error
+ */
+int net_iface_new(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface,
+ const char *type, void *arg);
+
+/**
+ * Remove an interface
+ *
+ * @param ctx the implementation specific context
+ * @param iface interface to delete
+ * @return int 0 on success, negative error code on error
+ */
+int net_iface_del(openvpn_net_ctx_t *ctx, const openvpn_net_iface_t *iface);
+
/**
* Bring interface up or down.
*
@@ -63,6 +63,34 @@ net_ctx_free(openvpn_net_ctx_t *ctx)
gc_free(&ctx->gc);
}
+int
+net_iface_new(openvpn_net_ctx_t *ctx, const char *iface, const char *type,
+ void *arg)
+{
+ struct argv argv = argv_new();
+
+ argv_printf(&argv, "%s link add %s type %s", iproute_path, iface, iface_type);
+ argv_msg(M_INFO, &argv);
+ openvpn_execve_check(&argv, ctx->es, S_FATAL, "Linux ip link add failed");
+
+ argv_free(&argv);
+
+ return 0;
+}
+
+int
+net_iface_del(openvpn_net_ctx_t *ctx, const char *iface)
+{
+ struct argv argv = argv_new();
+
+ argv_printf(&argv, "%s link del %s", iproute_path, iface);
+ openvpn_execve_check(&argv, ctx->es, 0, "Linux ip link del failed");
+
+ argv_free(&argv);
+
+ return 0;
+}
+
int
net_iface_up(openvpn_net_ctx_t *ctx, const char *iface, bool up)
{
@@ -56,6 +56,18 @@
#define NLMSG_TAIL(nmsg) \
((struct rtattr *)(((uint8_t *)(nmsg)) + NLMSG_ALIGN((nmsg)->nlmsg_len)))
+#define SITNL_NEST(_msg, _max_size, _attr) \
+ ({ \
+ struct rtattr *_nest = NLMSG_TAIL(_msg); \
+ SITNL_ADDATTR(_msg, _max_size, _attr, NULL, 0); \
+ _nest; \
+ })
+
+#define SITNL_NEST_END(_msg, _nest) \
+ { \
+ _nest->rta_len = (void *)NLMSG_TAIL(_msg) - (void *)_nest; \
+ }
+
/**
* Generic address data structure used to pass addresses and prefixes as
* argument to AF family agnostic functions
@@ -596,6 +608,7 @@ net_route_v6_best_gw(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
}
#ifdef ENABLE_SITNL
+
int
net_route_v4_best_gw(openvpn_net_ctx_t *ctx, const in_addr_t *dst,
in_addr_t *best_gw, char *best_iface)
@@ -1313,6 +1326,56 @@ net_route_v6_del(openvpn_net_ctx_t *ctx, const struct in6_addr *dst,
table, metric);
}
+
+int
+net_iface_new(openvpn_net_ctx_t *ctx, const char *iface, const char *type,
+ void *arg)
+{
+ struct sitnl_link_req req = { };
+ int ret = -1;
+
+ ASSERT(iface);
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
+ req.n.nlmsg_flags = NLM_F_REQUEST | NLM_F_CREATE | NLM_F_EXCL;
+ req.n.nlmsg_type = RTM_NEWLINK;
+
+ SITNL_ADDATTR(&req.n, sizeof(req), IFLA_IFNAME, iface, strlen(iface) + 1);
+
+ struct rtattr *linkinfo = SITNL_NEST(&req.n, sizeof(req), IFLA_LINKINFO);
+ SITNL_ADDATTR(&req.n, sizeof(req), IFLA_INFO_KIND, type, strlen(type) + 1);
+ SITNL_NEST_END(&req.n, linkinfo);
+
+ req.i.ifi_family = AF_PACKET;
+
+ msg(D_ROUTE, "%s: add %s type %s", __func__, iface, type);
+
+ ret = sitnl_send(&req.n, 0, 0, NULL, NULL);
+err:
+ return ret;
+}
+
+int
+net_iface_del(openvpn_net_ctx_t *ctx, const char *iface)
+{
+ struct sitnl_link_req req = { };
+ int ifindex = if_nametoindex(iface);
+
+ if (!ifindex)
+ return errno;
+
+ req.n.nlmsg_len = NLMSG_LENGTH(sizeof(req.i));
+ req.n.nlmsg_flags = NLM_F_REQUEST;
+ req.n.nlmsg_type = RTM_DELLINK;
+
+ req.i.ifi_family = AF_PACKET;
+ req.i.ifi_index = ifindex;
+
+ msg(D_ROUTE, "%s: delete %s", __func__, iface);
+
+ return sitnl_send(&req.n, 0, 0, NULL, NULL);
+}
+
#endif /* !ENABLE_SITNL */
#endif /* TARGET_LINUX */
@@ -13,6 +13,20 @@ net__iface_up(bool up)
return net_iface_up(NULL, iface, up);
}
+static int
+net__iface_new(const char *name, const char *type)
+{
+ printf("CMD: ip link add %s type %s\n", name, type);
+ return net_iface_new(NULL, name, type, NULL);
+}
+
+static int
+net__iface_del(const char *name)
+{
+ printf("CMD: ip link del %s\n", name);
+ return net_iface_del(NULL, name);
+}
+
static int
net__iface_mtu_set(int mtu)
{
@@ -191,7 +205,7 @@ net__route_v6_add_gw(const char *dst_str, int prefixlen, const char *gw_str,
static void
usage(char *name)
{
- printf("Usage: %s <0-7>\n", name);
+ printf("Usage: %s <0-9>\n", name);
}
int
@@ -243,6 +257,12 @@ main(int argc, char *argv[])
case 7:
return net__route_v6_add_gw("2001:cafe:babe::", 48, "2001::2", 600);
+ case 8:
+ return net__iface_new("dummy0815", "dummy");
+
+ case 9:
+ return net__iface_del("dummy0815");
+
default:
printf("invalid test: %d\n", test);
break;