From 0f1f6ce4d6e02618a38252a85525012f73991965 Mon Sep 17 00:00:00 2001 From: Mark Stapp Date: Fri, 25 Jan 2019 11:31:51 -0500 Subject: [PATCH] zebra: Dplane interface address install for non-netlink ioctl-based platform code for interface address installation Signed-off-by: Mark Stapp --- zebra/interface.c | 24 +++-- zebra/ioctl.c | 241 +++++++++++++++++++++++++++++++++++++++--- zebra/ioctl_solaris.c | 69 ++++++++---- 3 files changed, 292 insertions(+), 42 deletions(-) diff --git a/zebra/interface.c b/zebra/interface.c index 84815d7cd5..5106f0d22d 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -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; } diff --git a/zebra/ioctl.c b/zebra/ioctl.c index 45fad623e9..1466a1f1c4 100644 --- a/zebra/ioctl.c +++ b/zebra/ioctl.c @@ -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; diff --git a/zebra/ioctl_solaris.c b/zebra/ioctl_solaris.c index e95916c566..ccfa7a4a4c 100644 --- a/zebra/ioctl_solaris.c +++ b/zebra/ioctl_solaris.c @@ -38,9 +38,16 @@ #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; } -- 2.39.5