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 <philippe.guibert@6wind.com>
This commit is contained in:
Philippe Guibert 2018-02-22 19:10:32 +01:00
parent 0268f30e3c
commit 4db2161955
4 changed files with 49 additions and 7 deletions

View File

@ -146,7 +146,7 @@ static int if_get_hwaddr(struct interface *ifp)
ifreq.ifr_addr.sa_family = AF_INET; ifreq.ifr_addr.sa_family = AF_INET;
/* Fetch Hardware address if available. */ /* 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) if (ret < 0)
ifp->hw_addr_len = 0; ifp->hw_addr_len = 0;
else { else {

View File

@ -59,6 +59,7 @@ int if_ioctl(u_long request, caddr_t buffer)
sock = socket(AF_INET, SOCK_DGRAM, 0); sock = socket(AF_INET, SOCK_DGRAM, 0);
if (sock < 0) { if (sock < 0) {
int save_errno = errno; int save_errno = errno;
if (zserv_privs.change(ZPRIVS_LOWER)) if (zserv_privs.change(ZPRIVS_LOWER))
zlog_err("Can't lower privileges"); zlog_err("Can't lower privileges");
zlog_err("Cannot create UDP socket: %s", zlog_err("Cannot create UDP socket: %s",
@ -78,6 +79,39 @@ int if_ioctl(u_long request, caddr_t buffer)
return 0; 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 #ifndef HAVE_NETLINK
static int if_ioctl_ipv6(u_long request, caddr_t buffer) 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); sock = socket(AF_INET6, SOCK_DGRAM, 0);
if (sock < 0) { if (sock < 0) {
int save_errno = errno; int save_errno = errno;
if (zserv_privs.change(ZPRIVS_LOWER)) if (zserv_privs.change(ZPRIVS_LOWER))
zlog_err("Can't lower privileges"); zlog_err("Can't lower privileges");
zlog_err("Cannot create IPv6 datagram socket: %s", zlog_err("Cannot create IPv6 datagram socket: %s",
@ -122,7 +157,7 @@ void if_get_metric(struct interface *ifp)
ifreq_set_name(&ifreq, 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; return;
ifp->metric = ifreq.ifr_metric; ifp->metric = ifreq.ifr_metric;
if (ifp->metric == 0) if (ifp->metric == 0)
@ -140,7 +175,7 @@ void if_get_mtu(struct interface *ifp)
ifreq_set_name(&ifreq, ifp); ifreq_set_name(&ifreq, ifp);
#if defined(SIOCGIFMTU) #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)"); zlog_info("Can't lookup mtu by ioctl(SIOCGIFMTU)");
ifp->mtu6 = ifp->mtu = -1; ifp->mtu6 = ifp->mtu = -1;
return; return;
@ -376,9 +411,9 @@ void if_get_flags(struct interface *ifp)
ifreq_set_name(&ifreq, 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) { if (ret < 0) {
zlog_err("if_ioctl(SIOCGIFFLAGS) failed: %s", zlog_err("vrf_if_ioctl(SIOCGIFFLAGS) failed: %s",
safe_strerror(errno)); safe_strerror(errno));
return; return;
} }
@ -423,7 +458,7 @@ int if_set_flags(struct interface *ifp, uint64_t flags)
ifreq.ifr_flags = ifp->flags; ifreq.ifr_flags = ifp->flags;
ifreq.ifr_flags |= 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) { if (ret < 0) {
zlog_info("can't set interface flags"); 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 = ifp->flags;
ifreq.ifr_flags &= ~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) { if (ret < 0) {
zlog_info("can't unset interface flags"); zlog_info("can't unset interface flags");

View File

@ -25,6 +25,7 @@
/* Prototypes. */ /* Prototypes. */
extern void ifreq_set_name(struct ifreq *, struct interface *); extern void ifreq_set_name(struct ifreq *, struct interface *);
extern int if_ioctl(u_long, caddr_t); 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_set_flags(struct interface *, uint64_t);
extern int if_unset_flags(struct interface *, uint64_t); extern int if_unset_flags(struct interface *, uint64_t);

View File

@ -30,6 +30,7 @@
#include "log.h" #include "log.h"
#include "privs.h" #include "privs.h"
#include "vty.h" #include "vty.h"
#include "vrf.h"
#include "zebra/rib.h" #include "zebra/rib.h"
#include "zebra/rt.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); 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 */ /* call ioctl system call */
int if_ioctl(u_long request, caddr_t buffer) int if_ioctl(u_long request, caddr_t buffer)
{ {