From 4db21619552b3f6823bf1ae8103eac82aab628f7 Mon Sep 17 00:00:00 2001 From: Philippe Guibert Date: Thu, 22 Feb 2018 19:10:32 +0100 Subject: [PATCH] zebra: handle some ioctl operations for VRF A new API is available for interface ioctl operations on Linux: vrf_if_ioctl. This is the unified API that permits doing ioctl operations on a per interface basis. Signed-off-by: Philippe Guibert --- zebra/if_ioctl.c | 2 +- zebra/ioctl.c | 47 +++++++++++++++++++++++++++++++++++++------ zebra/ioctl.h | 1 + zebra/ioctl_solaris.c | 6 ++++++ 4 files changed, 49 insertions(+), 7 deletions(-) diff --git a/zebra/if_ioctl.c b/zebra/if_ioctl.c index 1d108886de..09fc085018 100644 --- a/zebra/if_ioctl.c +++ b/zebra/if_ioctl.c @@ -146,7 +146,7 @@ static int if_get_hwaddr(struct interface *ifp) ifreq.ifr_addr.sa_family = AF_INET; /* Fetch Hardware address if available. */ - ret = if_ioctl(SIOCGIFHWADDR, (caddr_t)&ifreq); + ret = vrf_if_ioctl(SIOCGIFHWADDR, (caddr_t)&ifreq, ifp->vrf_id); if (ret < 0) ifp->hw_addr_len = 0; else { diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 8e3a1d1a03..d07d37056e 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -59,6 +59,7 @@ int if_ioctl(u_long request, caddr_t buffer) sock = socket(AF_INET, SOCK_DGRAM, 0); if (sock < 0) { int save_errno = errno; + if (zserv_privs.change(ZPRIVS_LOWER)) zlog_err("Can't lower privileges"); zlog_err("Cannot create UDP socket: %s", @@ -78,6 +79,39 @@ int if_ioctl(u_long request, caddr_t buffer) return 0; } +/* call ioctl system call */ +int vrf_if_ioctl(u_long request, caddr_t buffer, vrf_id_t vrf_id) +{ + int sock; + int ret; + int err = 0; + + if (zserv_privs.change(ZPRIVS_RAISE)) + zlog_err("Can't raise privileges"); + sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL); + if (sock < 0) { + int save_errno = errno; + + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog_err("Can't lower privileges"); + zlog_err("Cannot create UDP socket: %s", + safe_strerror(save_errno)); + exit(1); + } + ret = vrf_ioctl(vrf_id, sock, request, buffer); + if (ret < 0) + err = errno; + if (zserv_privs.change(ZPRIVS_LOWER)) + zlog_err("Can't lower privileges"); + close(sock); + + if (ret < 0) { + errno = err; + return ret; + } + return 0; +} + #ifndef HAVE_NETLINK static int if_ioctl_ipv6(u_long request, caddr_t buffer) { @@ -90,6 +124,7 @@ static int if_ioctl_ipv6(u_long request, caddr_t buffer) sock = socket(AF_INET6, SOCK_DGRAM, 0); if (sock < 0) { int save_errno = errno; + if (zserv_privs.change(ZPRIVS_LOWER)) zlog_err("Can't lower privileges"); zlog_err("Cannot create IPv6 datagram socket: %s", @@ -122,7 +157,7 @@ void if_get_metric(struct interface *ifp) ifreq_set_name(&ifreq, ifp); - if (if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq) < 0) + if (vrf_if_ioctl(SIOCGIFMETRIC, (caddr_t)&ifreq, ifp->vrf_id) < 0) return; ifp->metric = ifreq.ifr_metric; if (ifp->metric == 0) @@ -140,7 +175,7 @@ void if_get_mtu(struct interface *ifp) ifreq_set_name(&ifreq, ifp); #if defined(SIOCGIFMTU) - if (if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq) < 0) { + if (vrf_if_ioctl(SIOCGIFMTU, (caddr_t)&ifreq, ifp->vrf_id) < 0) { zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)"); ifp->mtu6 = ifp->mtu = -1; return; @@ -376,9 +411,9 @@ void if_get_flags(struct interface *ifp) ifreq_set_name(&ifreq, ifp); - ret = if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq); + ret = vrf_if_ioctl(SIOCGIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id); if (ret < 0) { - zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", + zlog_err("vrf_if_ioctl(SIOCGIFFLAGS) failed: %s", safe_strerror(errno)); return; } @@ -423,7 +458,7 @@ int if_set_flags(struct interface *ifp, uint64_t flags) ifreq.ifr_flags = ifp->flags; ifreq.ifr_flags |= flags; - ret = if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq); + ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id); if (ret < 0) { zlog_info("can't set interface flags"); @@ -444,7 +479,7 @@ int if_unset_flags(struct interface *ifp, uint64_t flags) ifreq.ifr_flags = ifp->flags; ifreq.ifr_flags &= ~flags; - ret = if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq); + ret = vrf_if_ioctl(SIOCSIFFLAGS, (caddr_t)&ifreq, ifp->vrf_id); if (ret < 0) { zlog_info("can't unset interface flags"); diff --git a/zebra/ioctl.h b/zebra/ioctl.h index 02f8e6b880..1a6e14ed4d 100644 --- a/zebra/ioctl.h +++ b/zebra/ioctl.h @@ -25,6 +25,7 @@ /* Prototypes. */ extern void ifreq_set_name(struct ifreq *, struct interface *); extern int if_ioctl(u_long, caddr_t); +extern int vrf_if_ioctl(u_long request, caddr_t buffer, vrf_id_t vrf_id); extern int if_set_flags(struct interface *, uint64_t); extern int if_unset_flags(struct interface *, uint64_t); diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index e8b65925f8..f429c42440 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -30,6 +30,7 @@ #include "log.h" #include "privs.h" #include "vty.h" +#include "vrf.h" #include "zebra/rib.h" #include "zebra/rt.h" @@ -44,6 +45,11 @@ void lifreq_set_name(struct lifreq *lifreq, const char *ifname) strncpy(lifreq->lifr_name, ifname, IFNAMSIZ); } +int vrf_if_ioctl(u_long request, caddr_t buffer, vrf_id_t vrf_id) +{ + return if_ioctl(request, buffer); +} + /* call ioctl system call */ int if_ioctl(u_long request, caddr_t buffer) { -- 2.39.5