]> git.puffer.fish Git - mirror/frr.git/commitdiff
zebra: Dplane interface address install for non-netlink
authorMark Stapp <mjs@voltanet.io>
Fri, 25 Jan 2019 16:31:51 +0000 (11:31 -0500)
committerMark Stapp <mjs@voltanet.io>
Mon, 22 Apr 2019 17:49:27 +0000 (13:49 -0400)
ioctl-based platform code for interface address installation

Signed-off-by: Mark Stapp <mjs@voltanet.io>
zebra/interface.c
zebra/ioctl.c
zebra/ioctl_solaris.c

index 84815d7cd54db810b4820747813b9fa3507dfc07..5106f0d22d8cee8348dc8e68a25defbd4c829ba5 100644 (file)
@@ -441,7 +441,6 @@ static void if_addr_wakeup(struct interface *ifp)
        struct listnode *node, *nnode;
        struct connected *ifc;
        struct prefix *p;
-       int ret;
        enum zebra_dplane_result dplane_res;
 
        for (ALL_LIST_ELEMENTS(ifp->connected, node, nnode, ifc)) {
@@ -504,12 +503,14 @@ static void if_addr_wakeup(struct interface *ifp)
                                        if_refresh(ifp);
                                }
 
-                               ret = if_prefix_add_ipv6(ifp, ifc);
-                               if (ret < 0) {
+
+                               dplane_res = dplane_intf_addr_set(ifp, ifc);
+                               if (dplane_res ==
+                                   ZEBRA_DPLANE_REQUEST_FAILURE) {
                                        flog_err_sys(
                                                EC_ZEBRA_IFACE_ADDR_ADD_FAILED,
                                                "Can't set interface's address: %s",
-                                               safe_strerror(errno));
+                                               dplane_res2str(dplane_res));
                                        continue;
                                }
 
@@ -2881,6 +2882,7 @@ static int ipv6_address_install(struct vty *vty, struct interface *ifp,
        struct connected *ifc;
        struct prefix_ipv6 *p;
        int ret;
+       enum zebra_dplane_result dplane_res;
 
        if_data = ifp->info;
 
@@ -2927,11 +2929,10 @@ static int ipv6_address_install(struct vty *vty, struct interface *ifp,
                        if_refresh(ifp);
                }
 
-               ret = if_prefix_add_ipv6(ifp, ifc);
-
-               if (ret < 0) {
+               dplane_res = dplane_intf_addr_set(ifp, ifc);
+               if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
                        vty_out(vty, "%% Can't set interface IP address: %s.\n",
-                               safe_strerror(errno));
+                               dplane_res2str(dplane_res));
                        return CMD_WARNING_CONFIG_FAILED;
                }
 
@@ -2965,6 +2966,7 @@ static int ipv6_address_uninstall(struct vty *vty, struct interface *ifp,
        struct prefix_ipv6 cp;
        struct connected *ifc;
        int ret;
+       enum zebra_dplane_result dplane_res;
 
        /* Convert to prefix structure. */
        ret = str2prefix_ipv6(addr_str, &cp);
@@ -2995,10 +2997,10 @@ static int ipv6_address_uninstall(struct vty *vty, struct interface *ifp,
        }
 
        /* This is real route. */
-       ret = if_prefix_delete_ipv6(ifp, ifc);
-       if (ret < 0) {
+       dplane_res = dplane_intf_addr_unset(ifp, ifc);
+       if (dplane_res == ZEBRA_DPLANE_REQUEST_FAILURE) {
                vty_out(vty, "%% Can't unset interface IP address: %s.\n",
-                       safe_strerror(errno));
+                       dplane_res2str(dplane_res));
                return CMD_WARNING_CONFIG_FAILED;
        }
 
index 45fad623e9d9f16e818397d2b5adab1d9165228e..1466a1f1c479a25f2318fcec9dd9ae6ddcc8adce 100644 (file)
@@ -34,6 +34,7 @@
 #include "zebra/rt.h"
 #include "zebra/interface.h"
 #include "zebra/zebra_errors.h"
+#include "zebra/debug.h"
 
 #ifndef SUNOS_5
 
@@ -181,35 +182,159 @@ void if_get_mtu(struct interface *ifp)
 }
 
 /*
- * TODO -- stub handler for interface address programming via the zebra dplane,
- *         for non-netlink platforms.
+ * Handler for interface address programming via the zebra dplane,
+ * for non-netlink platforms. This handler dispatches to per-platform
+ * helpers, based on the operation requested.
  */
 #ifndef HAVE_NETLINK
 
+/* Prototypes: these are placed in this block so that they're only seen
+ * on non-netlink platforms.
+ */
+static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
+
 enum zebra_dplane_result kernel_address_update_ctx(
        struct zebra_dplane_ctx *ctx)
 {
-       return -1;
+       int ret = -1;
+       const struct prefix *p;
+
+       p = dplane_ctx_get_intf_addr(ctx);
+
+       if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) {
+               if (p->family == AF_INET)
+                       ret = if_set_prefix_ctx(ctx);
+               else
+                       ret = if_set_prefix6_ctx(ctx);
+       } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_UNINSTALL) {
+               if (p->family == AF_INET)
+                       ret = if_unset_prefix_ctx(ctx);
+               else
+                       ret = if_unset_prefix6_ctx(ctx);
+       } else {
+               if (IS_ZEBRA_DEBUG_DPLANE)
+                       zlog_debug("Invalid op in interface-addr install");
+       }
+
+       return (ret == 0 ?
+               ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
 }
 
 #endif /* !HAVE_NETLINK */
 
 #ifdef HAVE_NETLINK
-/* Interface address setting via netlink interface. */
-int if_set_prefix(struct interface *ifp, struct connected *ifc)
+
+/* TODO -- remove; no use of these apis with netlink any longer */
+
+#else /* ! HAVE_NETLINK */
+#ifdef HAVE_STRUCT_IFALIASREQ
+
+/*
+ * Helper for interface-addr install, non-netlink
+ */
+static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 {
-       return kernel_address_add_ipv4(ifp, ifc);
+       int ret;
+       struct ifaliasreq addreq;
+       struct sockaddr_in addr, mask, peer;
+       struct prefix_ipv4 *p;
+
+       p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
+
+       memset(&addreq, 0, sizeof(addreq));
+       strncpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
+               sizeof(addreq.ifra_name));
+
+       memset(&addr, 0, sizeof(struct sockaddr_in));
+       addr.sin_addr = p->prefix;
+       addr.sin_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       addr.sin_len = sizeof(struct sockaddr_in);
+#endif
+       memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
+
+       if (dplane_ctx_intf_is_connected(ctx)) {
+               p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx);
+               memset(&mask, 0, sizeof(struct sockaddr_in));
+               peer.sin_addr = p->prefix;
+               peer.sin_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+               peer.sin_len = sizeof(struct sockaddr_in);
+#endif
+               memcpy(&addreq.ifra_broadaddr, &peer,
+                      sizeof(struct sockaddr_in));
+       }
+
+       memset(&mask, 0, sizeof(struct sockaddr_in));
+       masklen2ip(p->prefixlen, &mask.sin_addr);
+       mask.sin_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       mask.sin_len = sizeof(struct sockaddr_in);
+#endif
+       memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in));
+
+       ret = if_ioctl(SIOCAIFADDR, (caddr_t)&addreq);
+       if (ret < 0)
+               return ret;
+       return 0;
+
 }
 
-/* Interface address is removed using netlink interface. */
-int if_unset_prefix(struct interface *ifp, struct connected *ifc)
+/*
+ * Helper for interface-addr un-install, non-netlink
+ */
+static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 {
-       return kernel_address_delete_ipv4(ifp, ifc);
+       int ret;
+       struct ifaliasreq addreq;
+       struct sockaddr_in addr, mask, peer;
+       struct prefix_ipv4 *p;
+
+       p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
+
+       memset(&addreq, 0, sizeof(addreq));
+       strncpy((char *)&addreq.ifra_name, dplane_ctx_get_ifname(ctx),
+               sizeof(addreq.ifra_name));
+
+       memset(&addr, 0, sizeof(struct sockaddr_in));
+       addr.sin_addr = p->prefix;
+       addr.sin_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       addr.sin_len = sizeof(struct sockaddr_in);
+#endif
+       memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in));
+
+       if (dplane_ctx_intf_is_connected(ctx)) {
+               p = (struct prefix_ipv4 *)dplane_ctx_get_intf_dest(ctx);
+               memset(&mask, 0, sizeof(struct sockaddr_in));
+               peer.sin_addr = p->prefix;
+               peer.sin_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+               peer.sin_len = sizeof(struct sockaddr_in);
+#endif
+               memcpy(&addreq.ifra_broadaddr, &peer,
+                      sizeof(struct sockaddr_in));
+       }
+
+       memset(&mask, 0, sizeof(struct sockaddr_in));
+       masklen2ip(p->prefixlen, &mask.sin_addr);
+       mask.sin_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       mask.sin_len = sizeof(struct sockaddr_in);
+#endif
+       memcpy(&addreq.ifra_mask, &mask, sizeof(struct sockaddr_in));
+
+       ret = if_ioctl(SIOCDIFADDR, (caddr_t)&addreq);
+       if (ret < 0)
+               return ret;
+       return 0;
 }
-#else /* ! HAVE_NETLINK */
-#ifdef HAVE_STRUCT_IFALIASREQ
+
 /* Set up interface's IP address, netmask (and broadcas? ).  *BSD may
-   has ifaliasreq structure.  */
+   have ifaliasreq structure.  */
 int if_set_prefix(struct interface *ifp, struct connected *ifc)
 {
        int ret;
@@ -517,6 +642,98 @@ int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
 #ifndef ND6_INFINITE_LIFETIME
 #define ND6_INFINITE_LIFETIME 0xffffffffL
 #endif /* ND6_INFINITE_LIFETIME */
+
+/*
+ * Helper for interface-addr install, non-netlink
+ */
+static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
+{
+       int ret;
+       struct in6_aliasreq addreq;
+       struct sockaddr_in6 addr;
+       struct sockaddr_in6 mask;
+       struct prefix_ipv6 *p;
+
+       p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx);
+
+       memset(&addreq, 0, sizeof(addreq));
+       strncpy((char *)&addreq.ifra_name,
+               dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
+
+       memset(&addr, 0, sizeof(struct sockaddr_in6));
+       addr.sin6_addr = p->prefix;
+       addr.sin6_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       addr.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+       memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6));
+
+       memset(&mask, 0, sizeof(struct sockaddr_in6));
+       masklen2ip6(p->prefixlen, &mask.sin6_addr);
+       mask.sin6_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       mask.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+       memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6));
+
+       addreq.ifra_lifetime.ia6t_vltime = 0xffffffff;
+       addreq.ifra_lifetime.ia6t_pltime = 0xffffffff;
+
+#ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
+       addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
+       addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+#endif
+
+       ret = if_ioctl_ipv6(SIOCAIFADDR_IN6, (caddr_t)&addreq);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+/*
+ * Helper for interface-addr un-install, non-netlink
+ */
+static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
+{
+       int ret;
+       struct in6_aliasreq addreq;
+       struct sockaddr_in6 addr;
+       struct sockaddr_in6 mask;
+       struct prefix_ipv6 *p;
+
+       p = (struct prefix_ipv6 *)dplane_ctx_get_intf_addr(ctx);
+
+       memset(&addreq, 0, sizeof(addreq));
+       strncpy((char *)&addreq.ifra_name,
+               dplane_ctx_get_ifname(ctx), sizeof(addreq.ifra_name));
+
+       memset(&addr, 0, sizeof(struct sockaddr_in6));
+       addr.sin6_addr = p->prefix;
+       addr.sin6_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       addr.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+       memcpy(&addreq.ifra_addr, &addr, sizeof(struct sockaddr_in6));
+
+       memset(&mask, 0, sizeof(struct sockaddr_in6));
+       masklen2ip6(p->prefixlen, &mask.sin6_addr);
+       mask.sin6_family = p->family;
+#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN
+       mask.sin6_len = sizeof(struct sockaddr_in6);
+#endif
+       memcpy(&addreq.ifra_prefixmask, &mask, sizeof(struct sockaddr_in6));
+
+#ifdef HAVE_STRUCT_IF6_ALIASREQ_IFRA_LIFETIME
+       addreq.ifra_lifetime.ia6t_pltime = ND6_INFINITE_LIFETIME;
+       addreq.ifra_lifetime.ia6t_vltime = ND6_INFINITE_LIFETIME;
+#endif
+
+       ret = if_ioctl_ipv6(SIOCDIFADDR_IN6, (caddr_t)&addreq);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
 int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
 {
        int ret;
index e95916c5667b08bd1884bb1cb6756c68e4d03bca..ccfa7a4a4c38f3111b9eb5f6fbf27aa0e1170986 100644 (file)
 #include "zebra/interface.h"
 #include "zebra/ioctl_solaris.h"
 #include "zebra/zebra_errors.h"
+#include "zebra/debug.h"
 
 extern struct zebra_privs_t zserv_privs;
 
+/* Prototypes */
+static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
+static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx);
+
 /* clear and set interface name string */
 void lifreq_set_name(struct lifreq *lifreq, const char *ifname)
 {
@@ -184,30 +191,51 @@ void if_get_mtu(struct interface *ifp)
 }
 
 /*
- * Stub for new dataplane interface-address modification path.
+ *
  */
-enum zebra_dplane_result kernel_address_update_ctx(struct zebra_dplane_ctx *ctx)
+enum zebra_dplane_result kernel_address_update_ctx(
+       struct zebra_dplane_ctx *ctx)
 {
-       return ZEBRA_DPLANE_REQUEST_FAILURE;
+       int ret = -1;
+       const struct prefix *p;
+
+       p = dplane_ctx_get_intf_addr(ctx);
+
+       if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_INSTALL) {
+               if (p->family == AF_INET)
+                       ret = if_set_prefix_ctx(ctx);
+               else
+                       ret = if_set_prefix6_ctx(ctx);
+       } else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ADDR_UNINSTALL) {
+               if (p->family == AF_INET)
+                       ret = if_unset_prefix_ctx(ctx);
+               else
+                       ret = if_unset_prefix6_ctx(ctx);
+       } else {
+               if (IS_ZEBRA_DEBUG_DPLANE)
+                       zlog_debug("Invalid op in interface-addr install");
+       }
+
+       return (ret == 0 ?
+               ZEBRA_DPLANE_REQUEST_SUCCESS : ZEBRA_DPLANE_REQUEST_FAILURE);
 }
 
 /* Set up interface's address, netmask (and broadcast? ).
    Solaris uses ifname:number semantics to set IP address aliases. */
-int if_set_prefix(struct interface *ifp, struct connected *ifc)
+static int if_set_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int ret;
        struct ifreq ifreq;
-       struct sockaddr_in addr;
-       struct sockaddr_in broad;
-       struct sockaddr_in mask;
+       struct sockaddr_in addr, broad, mask;
        struct prefix_ipv4 ifaddr;
        struct prefix_ipv4 *p;
 
-       p = (struct prefix_ipv4 *)ifc->address;
+       p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
        ifaddr = *p;
 
-       strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name));
+       strlcpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
+               sizeof(ifreq.ifr_name));
 
        addr.sin_addr = p->prefix;
        addr.sin_family = p->family;
@@ -221,7 +249,7 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc)
        /* We need mask for make broadcast addr. */
        masklen2ip(p->prefixlen, &mask.sin_addr);
 
-       if (if_is_broadcast(ifp)) {
+       if (dplane_ctx_intf_is_broadcast(ctx)) {
                apply_mask_ipv4(&ifaddr);
                addr.sin_addr = ifaddr.prefix;
 
@@ -249,16 +277,17 @@ int if_set_prefix(struct interface *ifp, struct connected *ifc)
 
 /* Set up interface's address, netmask (and broadcast).
    Solaris uses ifname:number semantics to set IP address aliases. */
-int if_unset_prefix(struct interface *ifp, struct connected *ifc)
+static int if_unset_prefix_ctx(const struct zebra_dplane_ctx *ctx)
 {
        int ret;
        struct ifreq ifreq;
        struct sockaddr_in addr;
        struct prefix_ipv4 *p;
 
-       p = (struct prefix_ipv4 *)ifc->address;
+       p = (struct prefix_ipv4 *)dplane_ctx_get_intf_addr(ctx);
 
-       strlcpy(ifreq.ifr_name, ifp->name, sizeof(ifreq.ifr_name));
+       strncpy(ifreq.ifr_name, dplane_ctx_get_ifname(ctx),
+               sizeof(ifreq.ifr_name));
 
        memset(&addr, 0, sizeof(struct sockaddr_in));
        addr.sin_family = p->family;
@@ -385,24 +414,26 @@ int if_unset_flags(struct interface *ifp, uint64_t flags)
 }
 
 /* Interface's address add/delete functions. */
-int if_prefix_add_ipv6(struct interface *ifp, struct connected *ifc)
+static int if_set_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
 {
        char addrbuf[PREFIX_STRLEN];
 
+       prefix2str(dplane_ctx_get_intf_addr(ctx), addrbuf, sizeof(addrbuf));
+
        flog_warn(EC_LIB_DEVELOPMENT, "Can't set %s on interface %s",
-                 prefix2str(ifc->address, addrbuf, sizeof(addrbuf)),
-                 ifp->name);
+                 addrbuf, dplane_ctx_get_ifname(ctx));
 
        return 0;
 }
 
-int if_prefix_delete_ipv6(struct interface *ifp, struct connected *ifc)
+static int if_unset_prefix6_ctx(const struct zebra_dplane_ctx *ctx)
 {
        char addrbuf[PREFIX_STRLEN];
 
+       prefix2str(dplane_ctx_get_intf_addr(ctx), addrbuf, sizeof(addrbuf));
+
        flog_warn(EC_LIB_DEVELOPMENT, "Can't delete %s on interface %s",
-                 prefix2str(ifc->address, addrbuf, sizeof(addrbuf)),
-                 ifp->name);
+                 addrbuf, dplane_ctx_get_ifname(ctx));
 
        return 0;
 }