git: 54418f79fd29 - main - ifconfig: switch IPv4/IPv6 address manipulations to Netlink
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Mon, 22 May 2023 13:46:16 UTC
The branch main has been updated by melifaro:
URL: https://cgit.FreeBSD.org/src/commit/?id=54418f79fd292e14abf121f87a3c790a17447971
commit 54418f79fd292e14abf121f87a3c790a17447971
Author: Alexander V. Chernikov <melifaro@FreeBSD.org>
AuthorDate: 2023-05-20 11:53:46 +0000
Commit: Alexander V. Chernikov <melifaro@FreeBSD.org>
CommitDate: 2023-05-22 13:45:33 +0000
ifconfig: switch IPv4/IPv6 address manipulations to Netlink
Subscribers: imp
Differential Revision: https://reviews.freebsd.org/D40182
---
sbin/ifconfig/af_inet.c | 184 +++++++++++++++++++++++++++++++++++++--
sbin/ifconfig/af_inet6.c | 152 +++++++++++++++++++++++++++++++-
sbin/ifconfig/af_link.c | 3 +
sbin/ifconfig/ifconfig.c | 102 ++++++++++++++++------
sbin/ifconfig/ifconfig.h | 22 +++--
sbin/ifconfig/ifconfig_netlink.c | 46 +++++++++-
6 files changed, 464 insertions(+), 45 deletions(-)
diff --git a/sbin/ifconfig/af_inet.c b/sbin/ifconfig/af_inet.c
index cb030dbc711b..ab2b01320d04 100644
--- a/sbin/ifconfig/af_inet.c
+++ b/sbin/ifconfig/af_inet.c
@@ -55,8 +55,26 @@ static const char rcsid[] =
#include "ifconfig.h"
#include "ifconfig_netlink.h"
+#ifdef WITHOUT_NETLINK
static struct in_aliasreq in_addreq;
static struct ifreq in_ridreq;
+#else
+struct in_px {
+ struct in_addr addr;
+ int plen;
+ bool addrset;
+ bool maskset;
+};
+struct in_pdata {
+ struct in_px addr;
+ struct in_px dst_addr;
+ struct in_px brd_addr;
+ uint32_t flags;
+ uint32_t vhid;
+};
+static struct in_pdata in_add, in_del;
+#endif
+
static char addr_buf[NI_MAXHOST]; /*for getnameinfo()*/
extern char *f_inet, *f_addr;
@@ -182,6 +200,8 @@ in_status_nl(struct ifconfig_args *args __unused, struct io_handler *h,
}
#endif
+
+#ifdef WITHOUT_NETLINK
#define SIN(x) ((struct sockaddr_in *) &(x))
static struct sockaddr_in *sintab[] = {
SIN(in_ridreq.ifr_addr), SIN(in_addreq.ifra_addr),
@@ -233,14 +253,156 @@ in_getaddr(const char *s, int which)
errx(1, "%s: bad value", s);
}
+#else
+
+static struct in_px *sintab_nl[] = {
+ &in_del.addr, /* RIDADDR */
+ &in_add.addr, /* ADDR */
+ NULL, /* MASK */
+ &in_add.dst_addr, /* DSTADDR*/
+ &in_add.brd_addr, /* BRDADDR*/
+};
+
+static void
+in_getip(const char *addr_str, struct in_addr *ip)
+{
+ struct hostent *hp;
+ struct netent *np;
+
+ if (inet_aton(addr_str, ip))
+ return;
+ if ((hp = gethostbyname(addr_str)) != NULL)
+ bcopy(hp->h_addr, (char *)ip,
+ MIN((size_t)hp->h_length, sizeof(ip)));
+ else if ((np = getnetbyname(addr_str)) != NULL)
+ *ip = inet_makeaddr(np->n_net, INADDR_ANY);
+ else
+ errx(1, "%s: bad value", addr_str);
+}
+
+static void
+in_getaddr(const char *s, int which)
+{
+ struct in_px *px = sintab_nl[which];
+
+ if (which == MASK) {
+ struct in_px *px_addr = sintab_nl[ADDR];
+ struct in_addr mask = {};
+
+ in_getip(s, &mask);
+ px_addr->plen = __bitcount32(mask.s_addr);
+ px_addr->maskset = true;
+ return;
+ }
+
+ if (which == ADDR) {
+ char *p = NULL;
+
+ if((p = strrchr(s, '/')) != NULL) {
+ const char *errstr;
+ /* address is `name/masklen' */
+ int masklen;
+ *p = '\0';
+ if (!isdigit(*(p + 1)))
+ errstr = "invalid";
+ else
+ masklen = (int)strtonum(p + 1, 0, 32, &errstr);
+ if (errstr != NULL) {
+ *p = '/';
+ errx(1, "%s: bad value (width %s)", s, errstr);
+ }
+ px->plen = masklen;
+ px->maskset = true;
+ }
+ }
+
+ in_getip(s, &px->addr);
+ px->addrset = true;
+}
+
+
+static int
+in_exec_nl(struct io_handler *h, int action, void *data)
+{
+ struct in_pdata *pdata = (struct in_pdata *)data;
+ struct snl_writer nw = {};
+
+ snl_init_writer(h->ss, &nw);
+ struct nlmsghdr *hdr = snl_create_msg_request(&nw, action);
+ struct ifaddrmsg *ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
+
+ ifahdr->ifa_family = AF_INET;
+ ifahdr->ifa_prefixlen = pdata->addr.plen;
+ ifahdr->ifa_index = if_nametoindex_nl(h->ss, name);
+
+ snl_add_msg_attr_ip4(&nw, IFA_LOCAL, &pdata->addr.addr);
+ if (action == NL_RTM_NEWADDR && pdata->dst_addr.addrset)
+ snl_add_msg_attr_ip4(&nw, IFA_ADDRESS, &pdata->dst_addr.addr);
+ if (action == NL_RTM_NEWADDR && pdata->brd_addr.addrset)
+ snl_add_msg_attr_ip4(&nw, IFA_BROADCAST, &pdata->brd_addr.addr);
+
+ int off = snl_add_msg_attr_nested(&nw, IFA_FREEBSD);
+ snl_add_msg_attr_u32(&nw, IFAF_FLAGS, pdata->flags);
+ if (pdata->vhid != 0)
+ snl_add_msg_attr_u32(&nw, IFAF_VHID, pdata->vhid);
+ snl_end_attr_nested(&nw, off);
+
+ if (!snl_finalize_msg(&nw) || !snl_send_message(h->ss, hdr))
+ return (0);
+
+ struct snl_errmsg_data e = {};
+ snl_read_reply_code(h->ss, hdr->nlmsg_seq, &e);
+ if (e.error_str != NULL)
+ warnx("%s(): %s", __func__, e.error_str);
+
+ return (e.error);
+}
+
+static void
+in_setdefaultmask_nl(void)
+{
+ struct in_px *px = sintab_nl[ADDR];
+
+ in_addr_t i = ntohl(px->addr.s_addr);
+
+ /*
+ * If netmask isn't supplied, use historical default.
+ * This is deprecated for interfaces other than loopback
+ * or point-to-point; warn in other cases. In the future
+ * we should return an error rather than warning.
+ */
+ if (IN_CLASSA(i))
+ px->plen = IN_CLASSA_NSHIFT;
+ else if (IN_CLASSB(i))
+ px->plen = IN_CLASSB_NSHIFT;
+ else
+ px->plen = IN_CLASSC_NSHIFT;
+ px->maskset = true;
+}
+#endif
+
+static void
+warn_nomask(ifflags)
+{
+ if ((ifflags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) {
+ warnx("WARNING: setting interface address without mask "
+ "is deprecated,\ndefault mask may not be correct.");
+ }
+}
+
static void
in_postproc(int s, const struct afswtch *afp, int newaddr, int ifflags)
{
- if (sintab[ADDR]->sin_len != 0 && sintab[MASK]->sin_len == 0 &&
- newaddr && (ifflags & (IFF_POINTOPOINT | IFF_LOOPBACK)) == 0) {
- warnx("WARNING: setting interface address without mask "
- "is deprecated,\ndefault mask may not be correct.");
+#ifdef WITHOUT_NETLINK
+ if (sintab[ADDR]->sin_len != 0 && sintab[MASK]->sin_len == 0 && newaddr) {
+ warn_nomask(ifflags);
+ }
+#else
+ if (sintab_nl[ADDR]->addrset && !sintab_nl[ADDR]->maskset && newaddr) {
+ warn_nomask(ifflags);
+ in_setdefaultmask_nl();
}
+#endif
}
static void
@@ -288,10 +450,13 @@ in_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
static void
in_set_vhid(int vhid)
{
+#ifdef WITHOUT_NETLINK
in_addreq.ifra_vhid = vhid;
+#else
+ in_add.vhid = (uint32_t)vhid;
+#endif
}
-
static struct afswtch af_inet = {
.af_name = "inet",
.af_af = AF_INET,
@@ -305,10 +470,19 @@ static struct afswtch af_inet = {
.af_status_tunnel = in_status_tunnel,
.af_settunnel = in_set_tunnel,
.af_setvhid = in_set_vhid,
+#ifdef WITHOUT_NETLINK
.af_difaddr = SIOCDIFADDR,
.af_aifaddr = SIOCAIFADDR,
.af_ridreq = &in_ridreq,
.af_addreq = &in_addreq,
+ .af_exec = af_exec_ioctl,
+#else
+ .af_difaddr = NL_RTM_DELADDR,
+ .af_aifaddr = NL_RTM_NEWADDR,
+ .af_ridreq = &in_del,
+ .af_addreq = &in_add,
+ .af_exec = in_exec_nl,
+#endif
};
static __constructor void
diff --git a/sbin/ifconfig/af_inet6.c b/sbin/ifconfig/af_inet6.c
index 1bb08c8a6a5a..c932087b4d86 100644
--- a/sbin/ifconfig/af_inet6.c
+++ b/sbin/ifconfig/af_inet6.c
@@ -59,10 +59,30 @@ static const char rcsid[] =
#include "ifconfig.h"
#include "ifconfig_netlink.h"
+#ifndef WITHOUT_NETLINK
+struct in6_px {
+ struct in6_addr addr;
+ int plen;
+ bool set;
+};
+struct in6_pdata {
+ struct in6_px addr;
+ struct in6_px dst_addr;
+ struct in6_addrlifetime lifetime;
+ uint32_t flags;
+ uint32_t vhid;
+};
+
+static struct in6_pdata in6_del;
+static struct in6_pdata in6_add = {
+ .lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME },
+};
+#else
static struct in6_ifreq in6_ridreq;
static struct in6_aliasreq in6_addreq =
{ .ifra_flags = 0,
.ifra_lifetime = { 0, 0, ND6_INFINITE_LIFETIME, ND6_INFINITE_LIFETIME } };
+#endif
static int ip6lifetime;
static int prefix(void *, int);
@@ -80,8 +100,16 @@ static void
setifprefixlen(const char *addr, int dummy __unused, int s,
const struct afswtch *afp)
{
+#ifdef WITHOUT_NETLINK
if (afp->af_getprefix != NULL)
afp->af_getprefix(addr, MASK);
+#else
+ int plen = strtol(addr, NULL, 10);
+
+ if ((plen < 0) || (plen > 128))
+ errx(1, "%s: bad value", addr);
+ in6_add.addr.plen = plen;
+#endif
explicit_prefix = 1;
}
@@ -92,10 +120,17 @@ setip6flags(const char *dummyaddr __unused, int flag, int dummysoc __unused,
if (afp->af_af != AF_INET6)
err(1, "address flags can be set only for inet6 addresses");
+#ifdef WITHOUT_NETLINK
if (flag < 0)
in6_addreq.ifra_flags &= ~(-flag);
else
in6_addreq.ifra_flags |= flag;
+#else
+ if (flag < 0)
+ in6_add.flags &= ~(-flag);
+ else
+ in6_add.flags |= flag;
+#endif
}
static void
@@ -105,6 +140,11 @@ setip6lifetime(const char *cmd, const char *val, int s,
struct timespec now;
time_t newval;
char *ep;
+#ifdef WITHOUT_NETLINK
+ struct in6_addrlifetime *lifetime = &in6_addreq.ifra_lifetime;
+#else
+ struct in6_addrlifetime *lifetime = &in6_add.lifetime;
+#endif
clock_gettime(CLOCK_MONOTONIC_FAST, &now);
newval = (time_t)strtoul(val, &ep, 0);
@@ -113,11 +153,11 @@ setip6lifetime(const char *cmd, const char *val, int s,
if (afp->af_af != AF_INET6)
errx(1, "%s not allowed for the AF", cmd);
if (strcmp(cmd, "vltime") == 0) {
- in6_addreq.ifra_lifetime.ia6t_expire = now.tv_sec + newval;
- in6_addreq.ifra_lifetime.ia6t_vltime = newval;
+ lifetime->ia6t_expire = now.tv_sec + newval;
+ lifetime->ia6t_vltime = newval;
} else if (strcmp(cmd, "pltime") == 0) {
- in6_addreq.ifra_lifetime.ia6t_preferred = now.tv_sec + newval;
- in6_addreq.ifra_lifetime.ia6t_pltime = newval;
+ lifetime->ia6t_preferred = now.tv_sec + newval;
+ lifetime->ia6t_pltime = newval;
}
}
@@ -146,7 +186,11 @@ setip6eui64(const char *cmd, int dummy __unused, int s,
if (afp->af_af != AF_INET6)
errx(EXIT_FAILURE, "%s not allowed for the AF", cmd);
+#ifdef WITHOUT_NETLINK
in6 = (struct in6_addr *)&in6_addreq.ifra_addr.sin6_addr;
+#else
+ in6 = &in6_add.addr.addr;
+#endif
if (memcmp(&in6addr_any.s6_addr[8], &in6->s6_addr[8], 8) != 0)
errx(EXIT_FAILURE, "interface index is already filled");
if (getifaddrs(&ifap) != 0)
@@ -374,8 +418,92 @@ in6_status_nl(struct ifconfig_args *args __unused, struct io_handler *h,
putchar('\n');
}
+
+static struct in6_px *sin6tab_nl[] = {
+ &in6_del.addr, /* RIDADDR */
+ &in6_add.addr, /* ADDR */
+ NULL, /* MASK */
+ &in6_add.dst_addr, /* DSTADDR*/
+};
+
+static void
+in6_getaddr(const char *addr_str, int which)
+{
+ struct in6_px *px = sin6tab_nl[which];
+
+ newaddr &= 1;
+
+ px->set = true;
+ px->plen = 128;
+ if (which == ADDR) {
+ char *p = NULL;
+ if((p = strrchr(addr_str, '/')) != NULL) {
+ *p = '\0';
+ int plen = strtol(p + 1, NULL, 10);
+ if (plen < 0 || plen > 128)
+ errx(1, "%s: bad value", p + 1);
+ px->plen = plen;
+ explicit_prefix = 1;
+ }
+ }
+
+ struct addrinfo hints = { .ai_family = AF_INET6 };
+ struct addrinfo *res;
+
+ int error = getaddrinfo(addr_str, NULL, &hints, &res);
+ if (error != 0) {
+ if (inet_pton(AF_INET6, addr_str, &px->addr) != 1)
+ errx(1, "%s: bad value", addr_str);
+ } else {
+ struct sockaddr_in6 *sin6;
+
+ sin6 = (struct sockaddr_in6 *)(void *)res->ai_addr;
+ px->addr = sin6->sin6_addr;
+ freeaddrinfo(res);
+ }
+}
+
+static int
+in6_exec_nl(struct io_handler *h, int action, void *data)
+{
+ struct in6_pdata *pdata = (struct in6_pdata *)data;
+ struct snl_writer nw = {};
+
+ snl_init_writer(h->ss, &nw);
+ struct nlmsghdr *hdr = snl_create_msg_request(&nw, action);
+ struct ifaddrmsg *ifahdr = snl_reserve_msg_object(&nw, struct ifaddrmsg);
+
+ ifahdr->ifa_family = AF_INET6;
+ ifahdr->ifa_prefixlen = pdata->addr.plen;
+ ifahdr->ifa_index = if_nametoindex_nl(h->ss, name);
+
+ snl_add_msg_attr_ip6(&nw, IFA_LOCAL, &pdata->addr.addr);
+ if (action == NL_RTM_NEWADDR && pdata->dst_addr.set)
+ snl_add_msg_attr_ip6(&nw, IFA_ADDRESS, &pdata->dst_addr.addr);
+
+ struct ifa_cacheinfo ci = {
+ .ifa_prefered = pdata->lifetime.ia6t_pltime,
+ .ifa_valid = pdata->lifetime.ia6t_vltime,
+ };
+ snl_add_msg_attr(&nw, IFA_CACHEINFO, sizeof(ci), &ci);
+
+ int off = snl_add_msg_attr_nested(&nw, IFA_FREEBSD);
+ snl_add_msg_attr_u32(&nw, IFAF_FLAGS, pdata->flags);
+ if (pdata->vhid != 0)
+ snl_add_msg_attr_u32(&nw, IFAF_VHID, pdata->vhid);
+ snl_end_attr_nested(&nw, off);
+
+ if (!snl_finalize_msg(&nw) || !snl_send_message(h->ss, hdr))
+ return (0);
+
+ struct snl_errmsg_data e = {};
+ snl_read_reply_code(h->ss, hdr->nlmsg_seq, &e);
+
+ return (e.error);
+}
#endif
+#ifdef WITHOUT_NETLINK
#define SIN6(x) ((struct sockaddr_in6 *) &(x))
static struct sockaddr_in6 *sin6tab[] = {
SIN6(in6_ridreq.ifr_addr), SIN6(in6_addreq.ifra_addr),
@@ -463,6 +591,7 @@ prefix(void *val, int size)
return(0);
return (plen);
}
+#endif
static char *
sec2str(time_t total)
@@ -558,7 +687,11 @@ in6_set_tunnel(int s, struct addrinfo *srcres, struct addrinfo *dstres)
static void
in6_set_vhid(int vhid)
{
+#ifdef WITHOUT_NETLINK
in6_addreq.ifra_vhid = vhid;
+#else
+ in6_add.vhid = (uint32_t)vhid;
+#endif
}
static struct cmd inet6_cmds[] = {
@@ -606,16 +739,27 @@ static struct afswtch af_inet6 = {
.af_status_nl = in6_status_nl,
#endif
.af_getaddr = in6_getaddr,
+#ifdef WITHOUT_NETLINK
.af_getprefix = in6_getprefix,
+#endif
.af_other_status = nd6_status,
.af_postproc = in6_postproc,
.af_status_tunnel = in6_status_tunnel,
.af_settunnel = in6_set_tunnel,
.af_setvhid = in6_set_vhid,
+#ifdef WITHOUT_NETLINK
.af_difaddr = SIOCDIFADDR_IN6,
.af_aifaddr = SIOCAIFADDR_IN6,
.af_ridreq = &in6_addreq,
.af_addreq = &in6_addreq,
+ .af_exec = af_exec_ioctl,
+#else
+ .af_difaddr = NL_RTM_DELADDR,
+ .af_aifaddr = NL_RTM_NEWADDR,
+ .af_ridreq = &in6_add,
+ .af_addreq = &in6_add,
+ .af_exec = in6_exec_nl,
+#endif
};
static void
diff --git a/sbin/ifconfig/af_link.c b/sbin/ifconfig/af_link.c
index 52295453b4f0..0d1f5b1f6147 100644
--- a/sbin/ifconfig/af_link.c
+++ b/sbin/ifconfig/af_link.c
@@ -229,6 +229,7 @@ static struct afswtch af_link = {
.af_getaddr = link_getaddr,
.af_aifaddr = SIOCSIFLLADDR,
.af_addreq = &link_ridreq,
+ .af_exec = af_exec_ioctl,
};
static struct afswtch af_ether = {
.af_name = "ether",
@@ -241,6 +242,7 @@ static struct afswtch af_ether = {
.af_getaddr = link_getaddr,
.af_aifaddr = SIOCSIFLLADDR,
.af_addreq = &link_ridreq,
+ .af_exec = af_exec_ioctl,
};
static struct afswtch af_lladdr = {
.af_name = "lladdr",
@@ -253,6 +255,7 @@ static struct afswtch af_lladdr = {
.af_getaddr = link_getaddr,
.af_aifaddr = SIOCSIFLLADDR,
.af_addreq = &link_ridreq,
+ .af_exec = af_exec_ioctl,
};
static __constructor void
diff --git a/sbin/ifconfig/ifconfig.c b/sbin/ifconfig/ifconfig.c
index c5e7b7befc72..3b63eac5574a 100644
--- a/sbin/ifconfig/ifconfig.c
+++ b/sbin/ifconfig/ifconfig.c
@@ -112,6 +112,7 @@ static void list_interfaces_ioctl(struct ifconfig_args *args);
static void status(struct ifconfig_args *args, const struct sockaddr_dl *sdl,
struct ifaddrs *ifa);
static _Noreturn void usage(void);
+static void Perrorc(const char *cmd, int error);
static int getifflags(const char *ifname, int us, bool err_ok);
@@ -541,6 +542,30 @@ args_parse(struct ifconfig_args *args, int argc, char *argv[])
verbose = args->verbose;
}
+static int
+ifconfig_wrapper(struct ifconfig_args *args, int iscreate,
+ const struct afswtch *uafp)
+{
+#ifdef WITHOUT_NETLINK
+ struct io_handler h = {};
+ return (ifconfig(args, &h, iscreate, uafp));
+#else
+ return (ifconfig_wrapper_nl(args, iscreate, uafp));
+#endif
+}
+
+static bool
+isargcreate(const char *arg)
+{
+ if (arg == NULL)
+ return (false);
+
+ if (strcmp(arg, "create") == 0 || strcmp(arg, "plumb") == 0)
+ return (true);
+
+ return (false);
+}
+
int
main(int ac, char *av[])
{
@@ -580,13 +605,12 @@ main(int ac, char *av[])
* right here as we would otherwise fail when trying
* to find the interface.
*/
- if (arg != NULL && (strcmp(arg, "create") == 0 ||
- strcmp(arg, "plumb") == 0)) {
+ if (isargcreate(arg)) {
iflen = strlcpy(name, args.ifname, sizeof(name));
if (iflen >= sizeof(name))
errx(1, "%s: cloning name too long",
args.ifname);
- ifconfig(args.argc, args.argv, 1, NULL);
+ ifconfig_wrapper(&args, 1, NULL);
exit(exit_code);
}
#ifdef JAIL
@@ -600,7 +624,7 @@ main(int ac, char *av[])
if (iflen >= sizeof(name))
errx(1, "%s: interface name too long",
args.ifname);
- ifconfig(args.argc, args.argv, 0, NULL);
+ ifconfig_wrapper(&args, 0, NULL);
exit(exit_code);
}
#endif
@@ -610,8 +634,7 @@ main(int ac, char *av[])
* Do not allow use `create` command as hostname if
* address family is not specified.
*/
- if (arg != NULL && (strcmp(arg, "create") == 0 ||
- strcmp(arg, "plumb") == 0)) {
+ if (isargcreate(arg)) {
if (args.argc == 1)
errx(1, "interface %s already exists",
args.ifname);
@@ -641,7 +664,7 @@ main(int ac, char *av[])
if (!(((flags & IFF_CANTCONFIG) != 0) ||
(args.downonly && (flags & IFF_UP) != 0) ||
(args.uponly && (flags & IFF_UP) == 0)))
- ifconfig(args.argc, args.argv, 0, args.afp);
+ ifconfig_wrapper(&args, 0, args.afp);
}
goto done;
}
@@ -769,7 +792,7 @@ list_interfaces_ioctl(struct ifconfig_args *args)
ifindex++;
if (args->argc > 0)
- ifconfig(args->argc, args->argv, 0, args->afp);
+ ifconfig_wrapper(args, 0, args->afp);
else
status(args, sdl, ifa);
}
@@ -968,31 +991,42 @@ static void setifdstaddr(const char *, int, int, const struct afswtch *);
static const struct cmd setifdstaddr_cmd =
DEF_CMD("ifdstaddr", 0, setifdstaddr);
+int
+af_exec_ioctl(struct io_handler *h, int action, void *data)
+{
+ struct ifreq *req = (struct ifreq *)data;
+
+ strlcpy(req->ifr_name, name, sizeof(req->ifr_name));
+ if (ioctl(h->s, action, req) == 0)
+ return (0);
+ return (errno);
+}
+
static void
-delifaddr(int s, const struct afswtch *afp)
+delifaddr(struct io_handler *h, const struct afswtch *afp)
{
- if (afp->af_ridreq == NULL || afp->af_difaddr == 0) {
+ int error;
+
+ if (afp->af_exec == NULL) {
warnx("interface %s cannot change %s addresses!",
name, afp->af_name);
clearaddr = 0;
return;
}
- strlcpy(((struct ifreq *)afp->af_ridreq)->ifr_name, name,
- sizeof ifr.ifr_name);
- int ret = ioctl(s, afp->af_difaddr, afp->af_ridreq);
- if (ret < 0) {
- if (errno == EADDRNOTAVAIL && (doalias >= 0)) {
+ afp->af_exec(h, afp->af_difaddr, afp->af_ridreq);
+ if (error != 0) {
+ if (error == EADDRNOTAVAIL && (doalias >= 0)) {
/* means no previous address for interface */
} else
- Perror("ioctl (SIOCDIFADDR)");
+ Perrorc("ioctl (SIOCDIFADDR)", error);
}
}
static void
-addifaddr(int s, const struct afswtch *afp)
+addifaddr(struct io_handler *h, const struct afswtch *afp)
{
- if (afp->af_addreq == NULL || afp->af_aifaddr == 0) {
+ if (afp->af_exec == NULL) {
warnx("interface %s cannot change %s addresses!",
name, afp->af_name);
newaddr = 0;
@@ -1000,21 +1034,24 @@ addifaddr(int s, const struct afswtch *afp)
}
if (setaddr || setmask) {
- strlcpy(((struct ifreq *)afp->af_addreq)->ifr_name, name,
- sizeof ifr.ifr_name);
- if (ioctl(s, afp->af_aifaddr, afp->af_addreq) < 0)
- Perror("ioctl (SIOCAIFADDR)");
+ int error = afp->af_exec(h, afp->af_aifaddr, afp->af_addreq);
+ if (error != 0)
+ Perrorc("ioctl (SIOCAIFADDR)", error);
}
}
int
-ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp)
+ifconfig(struct ifconfig_args *args, struct io_handler *h, int iscreate,
+ const struct afswtch *uafp)
{
const struct afswtch *afp, *nafp;
const struct cmd *p;
struct callback *cb;
int s;
+ int argc = args->argc;
+ char *const *argv = args->argv;
+
strlcpy(ifr.ifr_name, name, sizeof ifr.ifr_name);
afp = NULL;
if (uafp != NULL)
@@ -1127,10 +1164,11 @@ top:
/*
* Do deferred operations.
*/
+ h->s = s;
if (clearaddr)
- delifaddr(s, afp);
+ delifaddr(h, afp);
if (newaddr)
- addifaddr(s, afp);
+ addifaddr(h, afp);
close(s);
return(0);
@@ -1237,7 +1275,7 @@ setifbroadaddr(const char *addr, int dummy __unused, int s,
const struct afswtch *afp)
{
if (afp->af_getaddr != NULL)
- afp->af_getaddr(addr, DSTADDR);
+ afp->af_getaddr(addr, BRDADDR);
}
static void
@@ -1713,8 +1751,8 @@ tunnel_status(int s)
af_all_tunnel_status(s);
}
-void
-Perror(const char *cmd)
+static void
+Perrorc(const char *cmd, int error)
{
switch (errno) {
@@ -1727,10 +1765,16 @@ Perror(const char *cmd)
break;
default:
- err(1, "%s", cmd);
+ errc(1, error, "%s", cmd);
}
}
+void
+Perror(const char *cmd)
+{
+ Perrorc(cmd, errno);
+}
+
/*
* Print a value a la the %b format of the kernel's printf
*/
diff --git a/sbin/ifconfig/ifconfig.h b/sbin/ifconfig/ifconfig.h
index 7b2b88a4dfac..9d37a6e75eba 100644
--- a/sbin/ifconfig/ifconfig.h
+++ b/sbin/ifconfig/ifconfig.h
@@ -144,10 +144,15 @@ struct ifaddrs;
struct addrinfo;
enum {
- RIDADDR,
- ADDR,
- MASK,
- DSTADDR,
+ RIDADDR = 0,
+ ADDR = 1,
+ MASK = 2,
+ DSTADDR = 3,
+#ifdef WITHOUT_NETLINK
+ BRDADDR = 3,
+#else
+ BRDADDR = 4,
+#endif
};
struct snl_state;
@@ -164,6 +169,7 @@ struct io_handler {
typedef void af_setvhid_f(int vhid);
typedef void af_status_nl_f(struct ifconfig_args *args, struct io_handler *h,
if_link_t *link, if_addr_t *ifa);
+typedef int af_exec_f(struct io_handler *h, int action, void *data);
struct afswtch {
const char *af_name; /* as given on cmd line, e.g. "inet" */
@@ -190,6 +196,7 @@ struct afswtch {
void (*af_postproc)(int s, const struct afswtch *,
int newaddr, int ifflags);
af_setvhid_f *af_setvhid; /* Set CARP vhid for an address */
+ af_exec_f *af_exec; /* Handler to interact with kernel */
u_long af_difaddr; /* set dst if address ioctl */
u_long af_aifaddr; /* set if address ioctl */
void *af_ridreq; /* */
@@ -202,6 +209,7 @@ struct afswtch {
struct addrinfo *dstres);
};
void af_register(struct afswtch *);
+int af_exec_ioctl(struct io_handler *h, int action, void *data);
struct ifconfig_args {
bool all; /* Match everything */
@@ -259,7 +267,8 @@ void sfp_status(int s, struct ifreq *ifr, int verbose);
struct sockaddr_dl;
bool match_ether(const struct sockaddr_dl *sdl);
bool match_if_flags(struct ifconfig_args *args, int if_flags);
-int ifconfig(int argc, char *const *argv, int iscreate, const struct afswtch *uafp);
+int ifconfig(struct ifconfig_args *args, struct io_handler *h,
+ int iscreate, const struct afswtch *uafp);
bool group_member(const char *ifname, const char *match, const char *nomatch);
void print_ifcap(struct ifconfig_args *args, int s);
void tunnel_status(int s);
@@ -270,6 +279,9 @@ void print_metric(int s);
/* Netlink-related functions */
void list_interfaces_nl(struct ifconfig_args *args);
+int ifconfig_wrapper_nl(struct ifconfig_args *args, int iscreate,
+ const struct afswtch *uafp);
+uint32_t if_nametoindex_nl(struct snl_state *ss, const char *ifname);
/*
* XXX expose this so modules that neeed to know of any pending
diff --git a/sbin/ifconfig/ifconfig_netlink.c b/sbin/ifconfig/ifconfig_netlink.c
index 26a42b5866c5..598444d0d029 100644
--- a/sbin/ifconfig/ifconfig_netlink.c
+++ b/sbin/ifconfig/ifconfig_netlink.c
@@ -122,6 +122,22 @@ nl_init_socket(struct snl_state *ss)
err(1, "unable to open netlink socket");
}
+int
+ifconfig_wrapper_nl(struct ifconfig_args *args, int iscreate,
+ const struct afswtch *uafp)
+{
+ struct snl_state ss = {};
+ struct io_handler h = { .ss = &ss };
+
+ nl_init_socket(&ss);
+
+ int error = ifconfig(args, &h, iscreate, uafp);
+
+ snl_free(&ss);
+
+ return (error);
+}
+
struct ifa {
struct ifa *next;
uint32_t count;
@@ -186,6 +202,29 @@ prepare_ifmap(struct snl_state *ss)
return (ifmap);
}
+uint32_t
+if_nametoindex_nl(struct snl_state *ss, const char *ifname)
+{
+ struct snl_writer nw = {};
+ struct snl_parsed_link_simple link = {};
+
+ snl_init_writer(ss, &nw);
+ struct nlmsghdr *hdr = snl_create_msg_request(&nw, RTM_GETLINK);
+ snl_reserve_msg_object(&nw, struct ifinfomsg);
+ snl_add_msg_attr_string(&nw, IFLA_IFNAME, ifname);
+
+ if (!snl_finalize_msg(&nw) || !snl_send_message(ss, hdr))
+ return (0);
+
+ hdr = snl_read_reply(ss, hdr->nlmsg_seq);
+ if (hdr->nlmsg_type != NL_RTM_NEWLINK)
+ return (0);
+ if (!snl_parse_nlmsg(ss, hdr, &snl_rtm_link_parser_simple, &link))
+ return (0);
+
+ return (link.ifi_index);
+}
+
static void
prepare_ifaddrs(struct snl_state *ss, struct ifmap *ifmap)
{
@@ -415,8 +454,11 @@ list_interfaces_nl(struct ifconfig_args *args)
fputs(iface->link.ifla_ifname, stdout);
} else if (args->argc == 0)
status_nl(args, &h, iface);
- else
- ifconfig(args->argc, args->argv, 0, args->afp);
+ else {
+ struct io_handler hh = { .s = -1, .ss = &ss };
+
+ ifconfig(args, &hh, 0, args->afp);
+ }
}
if (args->namesonly)
printf("\n");