X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=zebra%2Frt_socket.c;h=539370a498c79a30f5e7c7d107162acef4bf203d;hb=18d10d885461eaf44fba87ed57a347b565e94f55;hp=346699198f9b8c15f22f724da4fdeead4fec6e22;hpb=0be9d44862758e039771982f347b8af4142ee876;p=mirror_frr.git diff --git a/zebra/rt_socket.c b/zebra/rt_socket.c index 346699198..539370a49 100644 --- a/zebra/rt_socket.c +++ b/zebra/rt_socket.c @@ -33,12 +33,14 @@ #include "log.h" #include "privs.h" #include "vxlan.h" +#include "lib_errors.h" #include "zebra/debug.h" #include "zebra/rib.h" #include "zebra/rt.h" #include "zebra/kernel_socket.h" #include "zebra/zebra_mpls.h" +#include "zebra/zebra_errors.h" extern struct zebra_privs_t zserv_privs; @@ -71,10 +73,10 @@ static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label, struct sockaddr_mpls *smpls) { if (nh_label->num_labels > 1) { - zlog_warn( - "%s: can't push %u labels at " - "once (maximum is 1)", - __func__, nh_label->num_labels); + flog_warn(EC_ZEBRA_MAX_LABELS_PUSH, + "%s: can't push %u labels at " + "once (maximum is 1)", + __func__, nh_label->num_labels); return -1; } @@ -87,167 +89,6 @@ static int kernel_rtm_add_labels(struct mpls_label_stack *nh_label, } #endif -/* Interface between zebra message and rtm message. */ -static int kernel_rtm_ipv4(int cmd, const struct prefix *p, - struct route_entry *re) - -{ - struct sockaddr_in *mask = NULL; - struct sockaddr_in sin_dest, sin_mask, sin_gate; -#ifdef __OpenBSD__ - struct sockaddr_mpls smpls; -#endif - union sockunion *smplsp = NULL; - struct nexthop *nexthop; - int nexthop_num = 0; - ifindex_t ifindex = 0; - int gate = 0; - int error; - char prefix_buf[PREFIX_STRLEN]; - enum blackhole_type bh_type = BLACKHOLE_UNSPEC; - - if (IS_ZEBRA_DEBUG_RIB) - prefix2str(p, prefix_buf, sizeof(prefix_buf)); - memset(&sin_dest, 0, sizeof(struct sockaddr_in)); - sin_dest.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_dest.sin_len = sizeof(struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - sin_dest.sin_addr = p->u.prefix4; - - memset(&sin_mask, 0, sizeof(struct sockaddr_in)); - - memset(&sin_gate, 0, sizeof(struct sockaddr_in)); - sin_gate.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_gate.sin_len = sizeof(struct sockaddr_in); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - - /* Make gateway. */ - for (ALL_NEXTHOPS(re->ng, nexthop)) { - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) - continue; - - gate = 0; - char gate_buf[INET_ADDRSTRLEN] = "NULL"; - - /* - * XXX We need to refrain from kernel operations in some cases, - * but this if statement seems overly cautious - what about - * other than ADD and DELETE? - */ - if ((cmd == RTM_ADD && NEXTHOP_IS_ACTIVE(nexthop->flags)) - || (cmd == RTM_DELETE - && CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB))) { - if (nexthop->type == NEXTHOP_TYPE_IPV4 - || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) { - sin_gate.sin_addr = nexthop->gate.ipv4; - gate = 1; - } - if (nexthop->type == NEXTHOP_TYPE_IFINDEX - || nexthop->type == NEXTHOP_TYPE_IPV4_IFINDEX) - ifindex = nexthop->ifindex; - if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) { - struct in_addr loopback; - loopback.s_addr = htonl(INADDR_LOOPBACK); - sin_gate.sin_addr = loopback; - bh_type = nexthop->bh_type; - gate = 1; - } - - if (gate && p->prefixlen == 32) - mask = NULL; - else { - masklen2ip(p->prefixlen, &sin_mask.sin_addr); - sin_mask.sin_family = AF_INET; -#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_mask.sin_len = - sin_masklen(sin_mask.sin_addr); -#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ - mask = &sin_mask; - } - -#ifdef __OpenBSD__ - if (nexthop->nh_label - && !kernel_rtm_add_labels(nexthop->nh_label, - &smpls)) - continue; - smplsp = (union sockunion *)&smpls; -#endif - - error = rtm_write(cmd, (union sockunion *)&sin_dest, - (union sockunion *)mask, - gate ? (union sockunion *)&sin_gate - : NULL, - smplsp, ifindex, bh_type, re->metric); - - if (IS_ZEBRA_DEBUG_RIB) { - if (!gate) { - zlog_debug( - "%s: %s: attention! gate not found for re %p", - __func__, prefix_buf, re); - route_entry_dump(p, NULL, re); - } else - inet_ntop(AF_INET, &sin_gate.sin_addr, - gate_buf, INET_ADDRSTRLEN); - } - - switch (error) { - /* We only flag nexthops as being in FIB if rtm_write() - * did its work. */ - case ZEBRA_ERR_NOERROR: - nexthop_num++; - if (IS_ZEBRA_DEBUG_RIB) - zlog_debug( - "%s: %s: successfully did NH %s", - __func__, prefix_buf, gate_buf); - break; - - /* The only valid case for this error is kernel's - * failure to install - * a multipath route, which is common for FreeBSD. This - * should be - * ignored silently, but logged as an error otherwise. - */ - case ZEBRA_ERR_RTEXIST: - if (cmd != RTM_ADD) - zlog_err( - "%s: rtm_write() returned %d for command %d", - __func__, error, cmd); - continue; - break; - - /* Given that our NEXTHOP_FLAG_FIB matches real kernel - * FIB, it isn't - * normal to get any other messages in ANY case. - */ - case ZEBRA_ERR_RTNOEXIST: - case ZEBRA_ERR_RTUNREACH: - default: - zlog_err( - "%s: %s: rtm_write() unexpectedly returned %d for command %s", - __func__, - prefix2str(p, prefix_buf, - sizeof(prefix_buf)), - error, - lookup_msg(rtm_type_str, cmd, NULL)); - break; - } - } /* if (cmd and flags make sense) */ - else if (IS_ZEBRA_DEBUG_RIB) - zlog_debug("%s: odd command %s for flags %d", __func__, - lookup_msg(rtm_type_str, cmd, NULL), - nexthop->flags); - } /* for (ALL_NEXTHOPS(...))*/ - - /* If there was no useful nexthop, then complain. */ - if (nexthop_num == 0 && IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("%s: No useful nexthops were found in RIB entry %p", - __func__, re); - - return 0; /*XXX*/ -} - #ifdef SIN6_LEN /* Calculate sin6_len value for netmask socket value. */ static int sin6_masklen(struct in6_addr mask) @@ -273,11 +114,11 @@ static int sin6_masklen(struct in6_addr mask) #endif /* SIN6_LEN */ /* Interface between zebra message and rtm message. */ -static int kernel_rtm_ipv6(int cmd, const struct prefix *p, - struct route_entry *re) +static int kernel_rtm(int cmd, const struct prefix *p, + const struct nexthop_group *ng, uint32_t metric) + { - struct sockaddr_in6 *mask; - struct sockaddr_in6 sin_dest, sin_mask, sin_gate; + union sockunion sin_dest, sin_mask, sin_gate; #ifdef __OpenBSD__ struct sockaddr_mpls smpls; #endif @@ -287,67 +128,129 @@ static int kernel_rtm_ipv6(int cmd, const struct prefix *p, ifindex_t ifindex = 0; int gate = 0; int error; + char prefix_buf[PREFIX_STRLEN]; enum blackhole_type bh_type = BLACKHOLE_UNSPEC; - memset(&sin_dest, 0, sizeof(struct sockaddr_in6)); - sin_dest.sin6_family = AF_INET6; -#ifdef SIN6_LEN - sin_dest.sin6_len = sizeof(struct sockaddr_in6); -#endif /* SIN6_LEN */ - sin_dest.sin6_addr = p->u.prefix6; + if (IS_ZEBRA_DEBUG_RIB) + prefix2str(p, prefix_buf, sizeof(prefix_buf)); + + /* + * We only have the ability to ADD or DELETE at this point + * in time. + */ + if (cmd != RTM_ADD && cmd != RTM_DELETE) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s odd command %s for flags %d", + __func__, prefix_buf, + lookup_msg(rtm_type_str, cmd, NULL), + nexthop->flags); + return 0; + } - memset(&sin_mask, 0, sizeof(struct sockaddr_in6)); + memset(&sin_dest, 0, sizeof(sin_dest)); + memset(&sin_gate, 0, sizeof(sin_gate)); + memset(&sin_mask, 0, sizeof(sin_mask)); - memset(&sin_gate, 0, sizeof(struct sockaddr_in6)); - sin_gate.sin6_family = AF_INET6; + switch (p->family) { + case AF_INET: + sin_dest.sin.sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sin_dest.sin.sin_len = sizeof(sin_dest); + sin_gate.sin.sin_len = sizeof(sin_gate); +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + sin_dest.sin.sin_addr = p->u.prefix4; + sin_gate.sin.sin_family = AF_INET; + break; + case AF_INET6: + sin_dest.sin6.sin6_family = AF_INET6; +#ifdef SIN6_LEN + sin_dest.sin6.sin6_len = sizeof(sin_dest); +#endif /* SIN6_LEN */ + sin_dest.sin6.sin6_addr = p->u.prefix6; + sin_gate.sin6.sin6_family = AF_INET6; #ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN - sin_gate.sin6_len = sizeof(struct sockaddr_in6); + sin_gate.sin6.sin6_len = sizeof(sin_gate); #endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + break; + } /* Make gateway. */ - for (ALL_NEXTHOPS(re->ng, nexthop)) { - if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE)) + for (ALL_NEXTHOPS_PTR(ng, nexthop)) { + /* + * We only want to use the actual good nexthops + */ + if (CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_RECURSIVE) || + !CHECK_FLAG(nexthop->flags, NEXTHOP_FLAG_ACTIVE)) continue; gate = 0; + char gate_buf[INET_ADDRSTRLEN] = "NULL"; - if ((cmd == RTM_ADD && NEXTHOP_IS_ACTIVE(nexthop->flags)) - || (cmd == RTM_DELETE)) { - if (nexthop->type == NEXTHOP_TYPE_IPV6 - || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) { - sin_gate.sin6_addr = nexthop->gate.ipv6; - gate = 1; - } - if (nexthop->type == NEXTHOP_TYPE_IFINDEX - || nexthop->type == NEXTHOP_TYPE_IPV6_IFINDEX) - ifindex = nexthop->ifindex; - - if (nexthop->type == NEXTHOP_TYPE_BLACKHOLE) - bh_type = nexthop->bh_type; - } - -/* Under kame set interface index to link local address. */ + switch (nexthop->type) { + case NEXTHOP_TYPE_IPV4: + case NEXTHOP_TYPE_IPV4_IFINDEX: + sin_gate.sin.sin_addr = nexthop->gate.ipv4; + sin_gate.sin.sin_family = AF_INET; + ifindex = nexthop->ifindex; + gate = 1; + break; + case NEXTHOP_TYPE_IPV6: + case NEXTHOP_TYPE_IPV6_IFINDEX: + sin_gate.sin6.sin6_addr = nexthop->gate.ipv6; + sin_gate.sin6.sin6_family = AF_INET6; + ifindex = nexthop->ifindex; +/* Under kame set interface index to link local address */ #ifdef KAME #define SET_IN6_LINKLOCAL_IFINDEX(a, i) \ - do { \ - (a).s6_addr[2] = ((i) >> 8) & 0xff; \ - (a).s6_addr[3] = (i)&0xff; \ - } while (0) - - if (gate && IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6_addr)) - SET_IN6_LINKLOCAL_IFINDEX(sin_gate.sin6_addr, ifindex); + do { \ + (a).s6_addr[2] = ((i) >> 8) & 0xff; \ + (a).s6_addr[3] = (i)&0xff; \ + } while (0) + + if (IN6_IS_ADDR_LINKLOCAL(&sin_gate.sin6.sin6_addr)) + SET_IN6_LINKLOCAL_IFINDEX( + sin_gate.sin6.sin6_addr, + ifindex); #endif /* KAME */ - if (gate && p->prefixlen == 128) - mask = NULL; - else { - masklen2ip6(p->prefixlen, &sin_mask.sin6_addr); - sin_mask.sin6_family = AF_INET6; + gate = 1; + break; + case NEXTHOP_TYPE_IFINDEX: + ifindex = nexthop->ifindex; + break; + case NEXTHOP_TYPE_BLACKHOLE: + bh_type = nexthop->bh_type; + switch (p->family) { + case AFI_IP: { + struct in_addr loopback; + loopback.s_addr = htonl(INADDR_LOOPBACK); + sin_gate.sin.sin_addr = loopback; + gate = 1; + } + break; + case AFI_IP6: + break; + } + } + + switch (p->family) { + case AF_INET: + masklen2ip(p->prefixlen, &sin_mask.sin.sin_addr); + sin_mask.sin.sin_family = AF_INET; +#ifdef HAVE_STRUCT_SOCKADDR_IN_SIN_LEN + sin_mask.sin.sin_len = sin_masklen( + sin_mask.sin.sin_addr); +#endif /* HAVE_STRUCT_SOCKADDR_IN_SIN_LEN */ + break; + case AF_INET6: + masklen2ip6(p->prefixlen, &sin_mask.sin6.sin6_addr); + sin_mask.sin6.sin6_family = AF_INET6; #ifdef SIN6_LEN - sin_mask.sin6_len = sin6_masklen(sin_mask.sin6_addr); + sin_mask.sin6.sin6_len = sin6_masklen( + sin_mask.sin6.sin6_addr); #endif /* SIN6_LEN */ - mask = &sin_mask; + break; } #ifdef __OpenBSD__ @@ -356,75 +259,115 @@ static int kernel_rtm_ipv6(int cmd, const struct prefix *p, continue; smplsp = (union sockunion *)&smpls; #endif + error = rtm_write(cmd, &sin_dest, &sin_mask, + gate ? &sin_gate : NULL, smplsp, + ifindex, bh_type, metric); + + if (IS_ZEBRA_DEBUG_KERNEL) { + if (!gate) { + zlog_debug("%s: %s: attention! gate not found for re", + __func__, prefix_buf); + } else + inet_ntop(p->family == AFI_IP ? AF_INET + : AF_INET6, + &sin_gate.sin.sin_addr, + gate_buf, INET_ADDRSTRLEN); + } + switch (error) { + /* We only flag nexthops as being in FIB if + * rtm_write() did its work. */ + case ZEBRA_ERR_NOERROR: + nexthop_num++; + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s: successfully did NH %s", + __func__, prefix_buf, gate_buf); + if (cmd == RTM_ADD) + SET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + break; + + /* The only valid case for this error is + * kernel's failure to install a multipath + * route, which is common for FreeBSD. This + * should be ignored silently, but logged as an error + * otherwise. + */ + case ZEBRA_ERR_RTEXIST: + if (cmd != RTM_ADD) + flog_err(EC_LIB_SYSTEM_CALL, + "%s: rtm_write() returned %d for command %d", + __func__, error, cmd); + continue; - error = rtm_write(cmd, (union sockunion *)&sin_dest, - (union sockunion *)mask, - gate ? (union sockunion *)&sin_gate : NULL, - smplsp, ifindex, bh_type, re->metric); - (void)error; - - nexthop_num++; - } + /* Note any unexpected status returns */ + default: + flog_err(EC_LIB_SYSTEM_CALL, + "%s: %s: rtm_write() unexpectedly returned %d for command %s", + __func__, + prefix2str(p, prefix_buf, + sizeof(prefix_buf)), + error, lookup_msg(rtm_type_str, cmd, NULL)); + break; + } + } /* for (ALL_NEXTHOPS(...))*/ - /* If there is no useful nexthop then return. */ + /* If there was no useful nexthop, then complain. */ if (nexthop_num == 0) { if (IS_ZEBRA_DEBUG_KERNEL) - zlog_debug("kernel_rtm_ipv6(): No useful nexthop."); - return 0; + zlog_debug("%s: No useful nexthops were found in RIB prefix %s", + __func__, prefix2str(p, prefix_buf, + sizeof(prefix_buf))); + return 1; } return 0; /*XXX*/ } -static int kernel_rtm(int cmd, const struct prefix *p, struct route_entry *re) -{ - switch (PREFIX_FAMILY(p)) { - case AF_INET: - return kernel_rtm_ipv4(cmd, p, re); - case AF_INET6: - return kernel_rtm_ipv6(cmd, p, re); - } - return 0; -} - -enum dp_req_result kernel_route_rib(struct route_node *rn, - const struct prefix *p, - const struct prefix *src_p, - struct route_entry *old, - struct route_entry *new) +/* + * Update or delete a prefix from the kernel, + * using info from a dataplane context struct. + */ +enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) { - int route = 0; + enum zebra_dplane_result res = ZEBRA_DPLANE_REQUEST_SUCCESS; - if (src_p && src_p->prefixlen) { + if (dplane_ctx_get_src(ctx) != NULL) { zlog_err("route add: IPv6 sourcedest routes unsupported!"); - return DP_REQUEST_FAILURE; + res = ZEBRA_DPLANE_REQUEST_FAILURE; + goto done; } - if (zserv_privs.change(ZPRIVS_RAISE)) - zlog_err("Can't raise privileges"); - - if (old) - route |= kernel_rtm(RTM_DELETE, p, old); - - if (new) - route |= kernel_rtm(RTM_ADD, p, new); - - if (zserv_privs.change(ZPRIVS_LOWER)) - zlog_err("Can't lower privileges"); + frr_elevate_privs(&zserv_privs) { + + if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_DELETE) + kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), + dplane_ctx_get_ng(ctx), + dplane_ctx_get_metric(ctx)); + else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_INSTALL) + kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx), + dplane_ctx_get_ng(ctx), + dplane_ctx_get_metric(ctx)); + else if (dplane_ctx_get_op(ctx) == DPLANE_OP_ROUTE_UPDATE) { + /* Must do delete and add separately - + * no update available + */ + kernel_rtm(RTM_DELETE, dplane_ctx_get_dest(ctx), + dplane_ctx_get_old_ng(ctx), + dplane_ctx_get_old_metric(ctx)); + + kernel_rtm(RTM_ADD, dplane_ctx_get_dest(ctx), + dplane_ctx_get_ng(ctx), + dplane_ctx_get_metric(ctx)); + } else { + zlog_err("Invalid routing socket update op %s (%u)", + dplane_op2str(dplane_ctx_get_op(ctx)), + dplane_ctx_get_op(ctx)); + res = ZEBRA_DPLANE_REQUEST_FAILURE; + } + } /* Elevated privs */ - if (new) { - kernel_route_rib_pass_fail( - rn, p, new, - (!route) ? DP_INSTALL_SUCCESS - : DP_INSTALL_FAILURE); - } else { - kernel_route_rib_pass_fail(rn, p, old, - (!route) - ? DP_DELETE_SUCCESS - : DP_DELETE_FAILURE); - } +done: - return DP_REQUEST_SUCCESS; + return res; } int kernel_neigh_update(int add, int ifindex, uint32_t addr, char *lla, @@ -450,13 +393,13 @@ int kernel_del_vtep(vni_t vni, struct interface *ifp, struct in_addr *vtep_ip) } int kernel_add_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, - struct in_addr vtep_ip, uint8_t sticky) + struct in_addr vtep_ip, bool sticky) { return 0; } int kernel_del_mac(struct interface *ifp, vlanid_t vid, struct ethaddr *mac, - struct in_addr vtep_ip, int local) + struct in_addr vtep_ip) { return 0; }