]> git.proxmox.com Git - mirror_frr.git/blobdiff - zebra/ioctl.c
isisd: implement the 'lsp-too-large' notification
[mirror_frr.git] / zebra / ioctl.c
index 58118ce006f014c9306b82e16816450e0c6abf96..ebe1edcaef0a77b11ce5cf394269e254a38d5195 100644 (file)
 #include "ioctl.h"
 #include "log.h"
 #include "privs.h"
+#include "lib_errors.h"
 
 #include "vty.h"
 #include "zebra/rib.h"
 #include "zebra/rt.h"
 #include "zebra/interface.h"
+#include "zebra/zebra_errors.h"
 
 #ifndef SUNOS_5
 
@@ -48,27 +50,22 @@ void ifreq_set_name(struct ifreq *ifreq, struct interface *ifp)
 }
 
 /* call ioctl system call */
-int if_ioctl(u_long request, caddr_t buffer)
+int if_ioctl(unsigned long request, caddr_t buffer)
 {
        int sock;
        int ret;
        int err = 0;
 
-       if (zserv_privs.change(ZPRIVS_RAISE))
-               zlog_err("Can't raise privileges");
-       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",
-                        safe_strerror(save_errno));
-               exit(1);
+       frr_elevate_privs(&zserv_privs) {
+               sock = socket(AF_INET, SOCK_DGRAM, 0);
+               if (sock < 0) {
+                       zlog_err("Cannot create UDP socket: %s",
+                                safe_strerror(errno));
+                       exit(1);
+               }
+               if ((ret = ioctl(sock, request, buffer)) < 0)
+                       err = errno;
        }
-       if ((ret = ioctl(sock, request, buffer)) < 0)
-               err = errno;
-       if (zserv_privs.change(ZPRIVS_LOWER))
-               zlog_err("Can't lower privileges");
        close(sock);
 
        if (ret < 0) {
@@ -78,28 +75,51 @@ int if_ioctl(u_long request, caddr_t buffer)
        return 0;
 }
 
-static int if_ioctl_ipv6(u_long request, caddr_t buffer)
+/* call ioctl system call */
+int vrf_if_ioctl(unsigned 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 = 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",
-                        safe_strerror(save_errno));
-               exit(1);
+       frr_elevate_privs(&zserv_privs) {
+               sock = vrf_socket(AF_INET, SOCK_DGRAM, 0, vrf_id, NULL);
+               if (sock < 0) {
+                       zlog_err("Cannot create UDP socket: %s",
+                                safe_strerror(errno));
+                       exit(1);
+               }
+               ret = vrf_ioctl(vrf_id, sock, request, buffer);
+               if (ret < 0)
+                       err = errno;
        }
+       close(sock);
 
-       if ((ret = ioctl(sock, request, buffer)) < 0)
-               err = errno;
-       if (zserv_privs.change(ZPRIVS_LOWER))
-               zlog_err("Can't lower privileges");
+       if (ret < 0) {
+               errno = err;
+               return ret;
+       }
+       return 0;
+}
+
+#ifndef HAVE_NETLINK
+static int if_ioctl_ipv6(unsigned long request, caddr_t buffer)
+{
+       int sock;
+       int ret;
+       int err = 0;
+
+       frr_elevate_privs(&zserv_privs) {
+               sock = socket(AF_INET6, SOCK_DGRAM, 0);
+               if (sock < 0) {
+                       zlog_err("Cannot create IPv6 datagram socket: %s",
+                                safe_strerror(errno));
+                       exit(1);
+               }
+
+               if ((ret = ioctl(sock, request, buffer)) < 0)
+                       err = errno;
+       }
        close(sock);
 
        if (ret < 0) {
@@ -108,6 +128,7 @@ static int if_ioctl_ipv6(u_long request, caddr_t buffer)
        }
        return 0;
 }
+#endif /* ! HAVE_NETLINK */
 
 /*
  * get interface metric
@@ -120,7 +141,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)
@@ -138,7 +159,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;
@@ -374,10 +395,11 @@ 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",
-                        safe_strerror(errno));
+               flog_err_sys(EC_LIB_SYSTEM_CALL,
+                            "vrf_if_ioctl(SIOCGIFFLAGS) failed: %s",
+                            safe_strerror(errno));
                return;
        }
 #ifdef HAVE_BSD_LINK_DETECT /* Detect BSD link-state at start-up */
@@ -393,9 +415,11 @@ void if_get_flags(struct interface *ifp)
                strncpy(ifmr.ifm_name, ifp->name, IFNAMSIZ);
 
                /* Seems not all interfaces implement this ioctl */
-               if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) < 0)
-                       zlog_err("if_ioctl(SIOCGIFMEDIA) failed: %s",
-                                safe_strerror(errno));
+               if (if_ioctl(SIOCGIFMEDIA, (caddr_t)&ifmr) == -1 &&
+                   errno != EINVAL)
+                       flog_err_sys(EC_LIB_SYSTEM_CALL,
+                                    "if_ioctl(SIOCGIFMEDIA) failed: %s",
+                                    safe_strerror(errno));
                else if (ifmr.ifm_status & IFM_AVALID) /* Link state is valid */
                {
                        if (ifmr.ifm_status & IFM_ACTIVE)
@@ -421,7 +445,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");
@@ -442,7 +466,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");
@@ -456,48 +480,23 @@ int if_unset_flags(struct interface *ifp, uint64_t flags)
 /* linux/include/net/ipv6.h */
 struct in6_ifreq {
        struct in6_addr ifr6_addr;
-       u_int32_t ifr6_prefixlen;
+       uint32_t ifr6_prefixlen;
        int ifr6_ifindex;
 };
 #endif /* _LINUX_IN6_H */
-
 /* Interface's address add/delete functions. */
 int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
 {
-       int ret;
-       struct prefix_ipv6 *p;
-       struct in6_ifreq ifreq;
-
-       p = (struct prefix_ipv6 *)ifc->address;
-
-       memset(&ifreq, 0, sizeof(struct in6_ifreq));
-
-       memcpy(&ifreq.ifr6_addr, &p->prefix, sizeof(struct in6_addr));
-       ifreq.ifr6_ifindex = ifp->ifindex;
-       ifreq.ifr6_prefixlen = p->prefixlen;
-
-       ret = if_ioctl_ipv6(SIOCSIFADDR, (caddr_t)&ifreq);
-
-       return ret;
+#ifdef HAVE_NETLINK
+       return kernel_address_add_ipv6(ifp, ifc);
+#endif /* HAVE_NETLINK */
 }
 
 int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
 {
-       int ret;
-       struct prefix_ipv6 *p;
-       struct in6_ifreq ifreq;
-
-       p = (struct prefix_ipv6 *)ifc->address;
-
-       memset(&ifreq, 0, sizeof(struct in6_ifreq));
-
-       memcpy(&ifreq.ifr6_addr, &p->prefix, sizeof(struct in6_addr));
-       ifreq.ifr6_ifindex = ifp->ifindex;
-       ifreq.ifr6_prefixlen = p->prefixlen;
-
-       ret = if_ioctl_ipv6(SIOCDIFADDR, (caddr_t)&ifreq);
-
-       return ret;
+#ifdef HAVE_NETLINK
+       return kernel_address_delete_ipv6(ifp, ifc);
+#endif /* HAVE_NETLINK */
 }
 #else /* LINUX_IPV6 */
 #ifdef HAVE_STRUCT_IN6_ALIASREQ