diff --git a/lib/prefix.h b/lib/prefix.h index 944c94f57f..c92f5cec5a 100644 --- a/lib/prefix.h +++ b/lib/prefix.h @@ -512,7 +512,7 @@ extern char *esi_to_str(const esi_t *esi, char *buf, int size); extern char *evpn_es_df_alg2str(uint8_t df_alg, char *buf, int buf_len); extern void prefix_evpn_hexdump(const struct prefix_evpn *p); -static inline int ipv6_martian(struct in6_addr *addr) +static inline int ipv6_martian(const struct in6_addr *addr) { struct in6_addr localhost_addr; @@ -527,7 +527,7 @@ static inline int ipv6_martian(struct in6_addr *addr) extern int macstr2prefix_evpn(const char *str, struct prefix_evpn *p); /* NOTE: This routine expects the address argument in network byte order. */ -static inline int ipv4_martian(struct in_addr *addr) +static inline int ipv4_martian(const struct in_addr *addr) { in_addr_t ip = ntohl(addr->s_addr); diff --git a/zebra/connected.c b/zebra/connected.c index e1dd0dbdff..0511b35185 100644 --- a/zebra/connected.c +++ b/zebra/connected.c @@ -307,9 +307,10 @@ void connected_up(struct interface *ifp, struct connected *ifc) } /* Add connected IPv4 route to the interface. */ -void connected_add_ipv4(struct interface *ifp, int flags, struct in_addr *addr, - uint16_t prefixlen, struct in_addr *dest, - const char *label, uint32_t metric) +void connected_add_ipv4(struct interface *ifp, int flags, + const struct in_addr *addr, uint16_t prefixlen, + const struct in_addr *dest, const char *label, + uint32_t metric) { struct prefix_ipv4 *p; struct connected *ifc; @@ -502,8 +503,8 @@ static void connected_delete_helper(struct connected *ifc, struct prefix *p) /* Delete connected IPv4 route to the interface. */ void connected_delete_ipv4(struct interface *ifp, int flags, - struct in_addr *addr, uint16_t prefixlen, - struct in_addr *dest) + const struct in_addr *addr, uint16_t prefixlen, + const struct in_addr *dest) { struct prefix p, d; struct connected *ifc; @@ -527,8 +528,9 @@ void connected_delete_ipv4(struct interface *ifp, int flags, } /* Add connected IPv6 route to the interface. */ -void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, - struct in6_addr *dest, uint16_t prefixlen, +void connected_add_ipv6(struct interface *ifp, int flags, + const struct in6_addr *addr, + const struct in6_addr *dest, uint16_t prefixlen, const char *label, uint32_t metric) { struct prefix_ipv6 *p; @@ -589,8 +591,9 @@ void connected_add_ipv6(struct interface *ifp, int flags, struct in6_addr *addr, connected_update(ifp, ifc); } -void connected_delete_ipv6(struct interface *ifp, struct in6_addr *address, - struct in6_addr *dest, uint16_t prefixlen) +void connected_delete_ipv6(struct interface *ifp, + const struct in6_addr *address, + const struct in6_addr *dest, uint16_t prefixlen) { struct prefix p, d; struct connected *ifc; diff --git a/zebra/connected.h b/zebra/connected.h index 14f6cb2db0..3ed9f6d5b9 100644 --- a/zebra/connected.h +++ b/zebra/connected.h @@ -39,13 +39,14 @@ extern struct connected *connected_check_ptp(struct interface *ifp, union prefixconstptr d); extern void connected_add_ipv4(struct interface *ifp, int flags, - struct in_addr *addr, uint16_t prefixlen, - struct in_addr *dest, const char *label, + const struct in_addr *addr, uint16_t prefixlen, + const struct in_addr *dest, const char *label, uint32_t metric); extern void connected_delete_ipv4(struct interface *ifp, int flags, - struct in_addr *addr, uint16_t prefixlen, - struct in_addr *dest); + const struct in_addr *addr, + uint16_t prefixlen, + const struct in_addr *dest); extern void connected_delete_ipv4_unnumbered(struct connected *ifc); @@ -53,12 +54,13 @@ extern void connected_up(struct interface *ifp, struct connected *ifc); extern void connected_down(struct interface *ifp, struct connected *ifc); extern void connected_add_ipv6(struct interface *ifp, int flags, - struct in6_addr *address, struct in6_addr *dest, - uint16_t prefixlen, const char *label, - uint32_t metric); + const struct in6_addr *address, + const struct in6_addr *dest, uint16_t prefixlen, + const char *label, uint32_t metric); extern void connected_delete_ipv6(struct interface *ifp, - struct in6_addr *address, - struct in6_addr *dest, uint16_t prefixlen); + const struct in6_addr *address, + const struct in6_addr *dest, + uint16_t prefixlen); extern int connected_is_unnumbered(struct interface *); diff --git a/zebra/if_netlink.c b/zebra/if_netlink.c index 8b3b788b72..8c528913e9 100644 --- a/zebra/if_netlink.c +++ b/zebra/if_netlink.c @@ -1443,7 +1443,6 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) NULL, ifa->ifa_prefixlen); } - /* * Linux kernel does not send route delete on interface down/addr del * so we have to re-process routes it owns (i.e. kernel routes) @@ -1454,6 +1453,215 @@ int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup) return 0; } +/* + * Parse and validate an incoming interface address change message, + * generating a dplane context object. + * This runs in the dplane pthread; the context is enqueued to the + * main pthread for processing. + */ +int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, + int startup /*ignored*/) +{ + int len; + struct ifaddrmsg *ifa; + struct rtattr *tb[IFA_MAX + 1]; + void *addr; + void *broad; + char *label = NULL; + uint32_t metric = METRIC_MAX; + uint32_t kernel_flags = 0; + struct zebra_dplane_ctx *ctx; + struct prefix p; + + ifa = NLMSG_DATA(h); + + /* Validate message types */ + if (h->nlmsg_type != RTM_NEWADDR && h->nlmsg_type != RTM_DELADDR) + return 0; + + if (ifa->ifa_family != AF_INET && ifa->ifa_family != AF_INET6) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s: Invalid address family: %u", + __func__, nl_msg_type_to_str(h->nlmsg_type), + ifa->ifa_family); + return 0; + } + + len = h->nlmsg_len - NLMSG_LENGTH(sizeof(struct ifaddrmsg)); + if (len < 0) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s: netlink msg bad size: %d %zu", + __func__, nl_msg_type_to_str(h->nlmsg_type), + h->nlmsg_len, + (size_t)NLMSG_LENGTH( + sizeof(struct ifaddrmsg))); + return -1; + } + + netlink_parse_rtattr(tb, IFA_MAX, IFA_RTA(ifa), len); + + /* Flags passed through */ + if (tb[IFA_FLAGS]) + kernel_flags = *(int *)RTA_DATA(tb[IFA_FLAGS]); + else + kernel_flags = ifa->ifa_flags; + + if (IS_ZEBRA_DEBUG_KERNEL) { /* remove this line to see initial ifcfg */ + char buf[PREFIX_STRLEN]; + + zlog_debug("%s: %s nsid %u ifindex %u flags 0x%x:", __func__, + nl_msg_type_to_str(h->nlmsg_type), ns_id, + ifa->ifa_index, kernel_flags); + if (tb[IFA_LOCAL]) + zlog_debug(" IFA_LOCAL %s/%d", + inet_ntop(ifa->ifa_family, + RTA_DATA(tb[IFA_LOCAL]), buf, + sizeof(buf)), + ifa->ifa_prefixlen); + if (tb[IFA_ADDRESS]) + zlog_debug(" IFA_ADDRESS %s/%d", + inet_ntop(ifa->ifa_family, + RTA_DATA(tb[IFA_ADDRESS]), buf, + sizeof(buf)), + ifa->ifa_prefixlen); + if (tb[IFA_BROADCAST]) + zlog_debug(" IFA_BROADCAST %s/%d", + inet_ntop(ifa->ifa_family, + RTA_DATA(tb[IFA_BROADCAST]), buf, + sizeof(buf)), + ifa->ifa_prefixlen); + if (tb[IFA_LABEL]) + zlog_debug(" IFA_LABEL %s", + (const char *)RTA_DATA(tb[IFA_LABEL])); + + if (tb[IFA_CACHEINFO]) { + struct ifa_cacheinfo *ci = RTA_DATA(tb[IFA_CACHEINFO]); + + zlog_debug(" IFA_CACHEINFO pref %d, valid %d", + ci->ifa_prefered, ci->ifa_valid); + } + } + + /* Validate prefix length */ + + if (ifa->ifa_family == AF_INET + && ifa->ifa_prefixlen > IPV4_MAX_BITLEN) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s: Invalid prefix length: %u", + __func__, nl_msg_type_to_str(h->nlmsg_type), + ifa->ifa_prefixlen); + return -1; + } + + if (ifa->ifa_family == AF_INET6) { + if (ifa->ifa_prefixlen > IPV6_MAX_BITLEN) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s: Invalid prefix length: %u", + __func__, + nl_msg_type_to_str(h->nlmsg_type), + ifa->ifa_prefixlen); + return -1; + } + + /* Only consider valid addresses; we'll not get a kernel + * notification till IPv6 DAD has completed, but at init + * time, FRR does query for and will receive all addresses. + */ + if (h->nlmsg_type == RTM_NEWADDR + && (kernel_flags & (IFA_F_DADFAILED | IFA_F_TENTATIVE))) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s: Invalid/tentative addr", + __func__, + nl_msg_type_to_str(h->nlmsg_type)); + return 0; + } + } + + /* logic copied from iproute2/ip/ipaddress.c:print_addrinfo() */ + if (tb[IFA_LOCAL] == NULL) + tb[IFA_LOCAL] = tb[IFA_ADDRESS]; + if (tb[IFA_ADDRESS] == NULL) + tb[IFA_ADDRESS] = tb[IFA_LOCAL]; + + /* local interface address */ + addr = (tb[IFA_LOCAL] ? RTA_DATA(tb[IFA_LOCAL]) : NULL); + + /* addr is primary key, SOL if we don't have one */ + if (addr == NULL) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s: No local interface address", + __func__, nl_msg_type_to_str(h->nlmsg_type)); + return -1; + } + + /* Allocate a context object, now that validation is done. */ + ctx = dplane_ctx_alloc(); + if (h->nlmsg_type == RTM_NEWADDR) + dplane_ctx_set_op(ctx, DPLANE_OP_INTF_ADDR_ADD); + else + dplane_ctx_set_op(ctx, DPLANE_OP_INTF_ADDR_DEL); + + dplane_ctx_set_ifindex(ctx, ifa->ifa_index); + dplane_ctx_set_ns_id(ctx, ns_id); + + /* Convert addr to prefix */ + memset(&p, 0, sizeof(p)); + p.family = ifa->ifa_family; + p.prefixlen = ifa->ifa_prefixlen; + if (p.family == AF_INET) + p.u.prefix4 = *(struct in_addr *)addr; + else + p.u.prefix6 = *(struct in6_addr *)addr; + + dplane_ctx_set_intf_addr(ctx, &p); + + /* is there a peer address? */ + if (tb[IFA_ADDRESS] + && memcmp(RTA_DATA(tb[IFA_ADDRESS]), RTA_DATA(tb[IFA_LOCAL]), + RTA_PAYLOAD(tb[IFA_ADDRESS]))) { + broad = RTA_DATA(tb[IFA_ADDRESS]); + dplane_ctx_intf_set_connected(ctx); + } else if (tb[IFA_BROADCAST]) { + /* seeking a broadcast address */ + broad = RTA_DATA(tb[IFA_BROADCAST]); + dplane_ctx_intf_set_broadcast(ctx); + } else + broad = NULL; + + if (broad) { + /* Convert addr to prefix */ + memset(&p, 0, sizeof(p)); + p.family = ifa->ifa_family; + p.prefixlen = ifa->ifa_prefixlen; + if (p.family == AF_INET) + p.u.prefix4 = *(struct in_addr *)broad; + else + p.u.prefix6 = *(struct in6_addr *)broad; + + dplane_ctx_set_intf_dest(ctx, &p); + } + + /* Flags. */ + if (kernel_flags & IFA_F_SECONDARY) + dplane_ctx_intf_set_secondary(ctx); + + /* Label */ + if (tb[IFA_LABEL]) { + label = (char *)RTA_DATA(tb[IFA_LABEL]); + dplane_ctx_set_intf_label(ctx, label); + } + + if (tb[IFA_RT_PRIORITY]) + metric = *(uint32_t *)RTA_DATA(tb[IFA_RT_PRIORITY]); + + dplane_ctx_set_intf_metric(ctx, metric); + + /* Enqueue ctx for main pthread to process */ + dplane_provider_enqueue_to_zebra(ctx); + + return 0; +} + int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup) { int len; diff --git a/zebra/if_netlink.h b/zebra/if_netlink.h index 4f09b10b75..a1ce7af8c7 100644 --- a/zebra/if_netlink.h +++ b/zebra/if_netlink.h @@ -29,6 +29,14 @@ extern "C" { extern int netlink_interface_addr(struct nlmsghdr *h, ns_id_t ns_id, int startup); + +/* + * Parse an incoming interface address change message, generate a dplane + * context object for processing. + */ +int netlink_interface_addr_dplane(struct nlmsghdr *h, ns_id_t ns_id, + int startup); + extern int netlink_link_change(struct nlmsghdr *h, ns_id_t ns_id, int startup); extern int interface_lookup_netlink(struct zebra_ns *zns); diff --git a/zebra/interface.c b/zebra/interface.c index 328ef3fa41..a68d00d55c 100644 --- a/zebra/interface.c +++ b/zebra/interface.c @@ -1205,6 +1205,109 @@ void zebra_if_set_protodown(struct interface *ifp, bool down) #endif } +/* + * Handle an interface addr event based on info in a dplane context object. + * This runs in the main pthread, using the info in the context object to + * modify an interface. + */ +void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx) +{ + struct interface *ifp; + uint8_t flags = 0; + const char *label = NULL; + ns_id_t ns_id; + struct zebra_ns *zns; + uint32_t metric = METRIC_MAX; + ifindex_t ifindex; + const struct prefix *addr, *dest = NULL; + enum dplane_op_e op; + + op = dplane_ctx_get_op(ctx); + ns_id = dplane_ctx_get_ns_id(ctx); + + zns = zebra_ns_lookup(ns_id); + if (zns == NULL) { + /* No ns - deleted maybe? */ + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: can't find zns id %u", __func__, ns_id); + goto done; + } + + ifindex = dplane_ctx_get_ifindex(ctx); + + ifp = if_lookup_by_index_per_ns(zns, ifindex); + if (ifp == NULL) { + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: can't find ifp at nsid %u index %d", + __func__, ns_id, ifindex); + goto done; + } + + addr = dplane_ctx_get_intf_addr(ctx); + + if (IS_ZEBRA_DEBUG_KERNEL) + zlog_debug("%s: %s: ifindex %u, addr %pFX", __func__, + dplane_op2str(op), ifindex, addr); + + /* Is there a peer or broadcast address? */ + dest = dplane_ctx_get_intf_dest(ctx); + if (dest->prefixlen == 0) + dest = NULL; + + if (dplane_ctx_intf_is_connected(ctx)) + SET_FLAG(flags, ZEBRA_IFA_PEER); + + /* Flags. */ + if (dplane_ctx_intf_is_secondary(ctx)) + SET_FLAG(flags, ZEBRA_IFA_SECONDARY); + + /* Label? */ + if (dplane_ctx_intf_has_label(ctx)) + label = dplane_ctx_get_intf_label(ctx); + + if (label && strcmp(ifp->name, label) == 0) + label = NULL; + + metric = dplane_ctx_get_intf_metric(ctx); + + /* Register interface address to the interface. */ + if (addr->family == AF_INET) { + if (op == DPLANE_OP_INTF_ADDR_ADD) + connected_add_ipv4( + ifp, flags, &addr->u.prefix4, addr->prefixlen, + dest ? &dest->u.prefix4 : NULL, label, metric); + else if (CHECK_FLAG(flags, ZEBRA_IFA_PEER)) { + /* Delete with a peer address */ + connected_delete_ipv4(ifp, flags, &addr->u.prefix4, + addr->prefixlen, + &dest->u.prefix4); + } else + connected_delete_ipv4(ifp, flags, &addr->u.prefix4, + addr->prefixlen, NULL); + } + + if (addr->family == AF_INET6) { + if (op == DPLANE_OP_INTF_ADDR_ADD) { + connected_add_ipv6(ifp, flags, &addr->u.prefix6, + dest ? &dest->u.prefix6 : NULL, + addr->prefixlen, label, metric); + } else + connected_delete_ipv6(ifp, &addr->u.prefix6, NULL, + addr->prefixlen); + } + + /* + * Linux kernel does not send route delete on interface down/addr del + * so we have to re-process routes it owns (i.e. kernel routes) + */ + if (op != DPLANE_OP_INTF_ADDR_ADD) + rib_update(RIB_UPDATE_KERNEL); + +done: + /* We're responsible for the ctx object */ + dplane_ctx_fini(&ctx); +} + /* Dump if address information to vty. */ static void connected_dump_vty(struct vty *vty, json_object *json, struct connected *connected) diff --git a/zebra/interface.h b/zebra/interface.h index d86bc68ef0..23e22bdda8 100644 --- a/zebra/interface.h +++ b/zebra/interface.h @@ -513,6 +513,7 @@ extern void zebra_l2_map_slave_to_bond(struct zebra_if *zif, vrf_id_t vrf); extern void zebra_l2_unmap_slave_from_bond(struct zebra_if *zif); extern const char *zebra_protodown_rc_str(enum protodown_reasons protodown_rc, char *pd_buf, uint32_t pd_buf_len); +void zebra_if_addr_update_ctx(struct zebra_dplane_ctx *ctx); #ifdef HAVE_PROC_NET_DEV extern void ifstat_update_proc(void); diff --git a/zebra/kernel_netlink.c b/zebra/kernel_netlink.c index effec24c1f..602bdc1dc5 100644 --- a/zebra/kernel_netlink.c +++ b/zebra/kernel_netlink.c @@ -324,6 +324,10 @@ static int netlink_socket(struct nlsock *nl, unsigned long groups, return ret; } +/* + * Dispatch an incoming netlink message; used by the zebra main pthread's + * netlink event reader. + */ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, int startup) { @@ -345,10 +349,6 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return netlink_link_change(h, ns_id, startup); case RTM_DELLINK: return netlink_link_change(h, ns_id, startup); - case RTM_NEWADDR: - return netlink_interface_addr(h, ns_id, startup); - case RTM_DELADDR: - return netlink_interface_addr(h, ns_id, startup); case RTM_NEWNEIGH: case RTM_DELNEIGH: case RTM_GETNEIGH: @@ -361,6 +361,12 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return netlink_nexthop_change(h, ns_id, startup); case RTM_DELNEXTHOP: return netlink_nexthop_change(h, ns_id, startup); + + /* Messages handled in the dplane thread */ + case RTM_NEWADDR: + case RTM_DELADDR: + return 0; + default: /* * If we have received this message then @@ -378,6 +384,32 @@ static int netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, return 0; } +/* + * Dispatch an incoming netlink message; used by the dataplane pthread's + * netlink event reader code. + */ +static int dplane_netlink_information_fetch(struct nlmsghdr *h, ns_id_t ns_id, + int startup) +{ + /* + * Dispatch the incoming messages that the dplane pthread handles + */ + switch (h->nlmsg_type) { + case RTM_NEWADDR: + case RTM_DELADDR: + return netlink_interface_addr_dplane(h, ns_id, startup); + + /* TODO */ + case RTM_NEWLINK: + case RTM_DELLINK: + + default: + break; + } + + return 0; +} + static int kernel_read(struct thread *thread) { struct zebra_ns *zns = (struct zebra_ns *)THREAD_ARG(thread); @@ -388,13 +420,24 @@ static int kernel_read(struct thread *thread) netlink_parse_info(netlink_information_fetch, &zns->netlink, &dp_info, 5, 0); - zns->t_netlink = NULL; + thread_add_read(zrouter.master, kernel_read, zns, zns->netlink.sock, &zns->t_netlink); return 0; } +/* + * Called by the dplane pthread to read incoming OS messages and dispatch them. + */ +int kernel_dplane_read(struct zebra_dplane_info *info) +{ + netlink_parse_info(dplane_netlink_information_fetch, &info->nls, info, + 5, 0); + + return 0; +} + /* * Filter out messages from self that occur on listener socket, * caused by our actions on the command socket(s) @@ -408,7 +451,7 @@ static int kernel_read(struct thread *thread) * so that we only had to write one way to handle incoming * address add/delete changes. */ -static void netlink_install_filter(int sock, __u32 pid, __u32 dplane_pid) +static void netlink_install_filter(int sock, uint32_t pid, uint32_t dplane_pid) { /* * BPF_JUMP instructions and where you jump to are based upon @@ -476,8 +519,8 @@ static void netlink_install_filter(int sock, __u32 pid, __u32 dplane_pid) safe_strerror(errno)); } -void netlink_parse_rtattr_flags(struct rtattr **tb, int max, - struct rtattr *rta, int len, unsigned short flags) +void netlink_parse_rtattr_flags(struct rtattr **tb, int max, struct rtattr *rta, + int len, unsigned short flags) { unsigned short type; @@ -799,8 +842,7 @@ static int netlink_recv_msg(const struct nlsock *nl, struct msghdr msg, * ignored, -1 otherwise. */ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h, - const struct zebra_dplane_info *zns, - bool startup) + bool is_cmd, bool startup) { struct nlmsgerr *err = (struct nlmsgerr *)NLMSG_DATA(h); int errnum = err->error; @@ -833,7 +875,7 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h, } /* Deal with errors that occur because of races in link handling. */ - if (zns->is_cmd + if (is_cmd && ((msg_type == RTM_DELROUTE && (-errnum == ENODEV || -errnum == ESRCH)) || (msg_type == RTM_NEWROUTE @@ -852,7 +894,7 @@ static int netlink_parse_error(const struct nlsock *nl, struct nlmsghdr *h, * do not log these as an error. */ if (msg_type == RTM_DELNEIGH - || (zns->is_cmd && msg_type == RTM_NEWROUTE + || (is_cmd && msg_type == RTM_NEWROUTE && (-errnum == ESRCH || -errnum == ENETUNREACH))) { /* * This is known to happen in some situations, don't log as @@ -924,8 +966,9 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), /* Error handling. */ if (h->nlmsg_type == NLMSG_ERROR) { - int err = netlink_parse_error(nl, h, zns, - startup); + int err = netlink_parse_error( + nl, h, zns->is_cmd, startup); + if (err == 1) { if (!(h->nlmsg_flags & NLM_F_MULTI)) return 0; @@ -937,8 +980,8 @@ int netlink_parse_info(int (*filter)(struct nlmsghdr *, ns_id_t, int), /* OK we got netlink message. */ if (IS_ZEBRA_DEBUG_KERNEL) zlog_debug( - "netlink_parse_info: %s type %s(%u), len=%d, seq=%u, pid=%u", - nl->name, + "%s: %s type %s(%u), len=%d, seq=%u, pid=%u", + __func__, nl->name, nl_msg_type_to_str(h->nlmsg_type), h->nlmsg_type, h->nlmsg_len, h->nlmsg_seq, h->nlmsg_pid); @@ -1140,7 +1183,8 @@ static int nl_batch_read_resp(struct nl_batch *bth) } if (h->nlmsg_type == NLMSG_ERROR) { - int err = netlink_parse_error(nl, h, bth->zns, 0); + int err = netlink_parse_error(nl, h, bth->zns->is_cmd, + false); if (err == -1) dplane_ctx_set_status( @@ -1359,6 +1403,8 @@ static enum netlink_msg_status nl_put_msg(struct nl_batch *bth, case DPLANE_OP_GRE_SET: return netlink_put_gre_set_msg(bth, ctx); + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: case DPLANE_OP_NONE: return FRR_NETLINK_ERROR; } @@ -1455,12 +1501,25 @@ void kernel_init(struct zebra_ns *zns) exit(-1); } - snprintf(zns->netlink_dplane.name, sizeof(zns->netlink_dplane.name), - "netlink-dp (NS %u)", zns->ns_id); - zns->netlink_dplane.sock = -1; - if (netlink_socket(&zns->netlink_dplane, 0, zns->ns_id) < 0) { + /* Outbound socket for dplane programming of the host OS. */ + snprintf(zns->netlink_dplane_out.name, + sizeof(zns->netlink_dplane_out.name), "netlink-dp (NS %u)", + zns->ns_id); + zns->netlink_dplane_out.sock = -1; + if (netlink_socket(&zns->netlink_dplane_out, 0, zns->ns_id) < 0) { zlog_err("Failure to create %s socket", - zns->netlink_dplane.name); + zns->netlink_dplane_out.name); + exit(-1); + } + + /* Inbound socket for OS events coming to the dplane. */ + snprintf(zns->netlink_dplane_in.name, + sizeof(zns->netlink_dplane_in.name), "netlink-dp-in (NS %u)", + zns->ns_id); + zns->netlink_dplane_in.sock = -1; + if (netlink_socket(&zns->netlink_dplane_in, groups, zns->ns_id) < 0) { + zlog_err("Failure to create %s socket", + zns->netlink_dplane_in.name); exit(-1); } @@ -1483,8 +1542,8 @@ void kernel_init(struct zebra_ns *zns) errno, safe_strerror(errno)); one = 1; - ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_EXT_ACK, - &one, sizeof(one)); + ret = setsockopt(zns->netlink_dplane_out.sock, SOL_NETLINK, + NETLINK_EXT_ACK, &one, sizeof(one)); if (ret < 0) zlog_notice("Registration for extended dp ACK failed : %d %s", @@ -1496,8 +1555,8 @@ void kernel_init(struct zebra_ns *zns) * setsockopt fails, ignore the error. */ one = 1; - ret = setsockopt(zns->netlink_dplane.sock, SOL_NETLINK, NETLINK_CAP_ACK, - &one, sizeof(one)); + ret = setsockopt(zns->netlink_dplane_out.sock, SOL_NETLINK, + NETLINK_CAP_ACK, &one, sizeof(one)); if (ret < 0) zlog_notice( "Registration for reduced ACK packet size failed, probably running an early kernel"); @@ -1512,20 +1571,33 @@ void kernel_init(struct zebra_ns *zns) zlog_err("Can't set %s socket error: %s(%d)", zns->netlink_cmd.name, safe_strerror(errno), errno); - if (fcntl(zns->netlink_dplane.sock, F_SETFL, O_NONBLOCK) < 0) + if (fcntl(zns->netlink_dplane_out.sock, F_SETFL, O_NONBLOCK) < 0) zlog_err("Can't set %s socket error: %s(%d)", - zns->netlink_dplane.name, safe_strerror(errno), errno); + zns->netlink_dplane_out.name, safe_strerror(errno), + errno); + + if (fcntl(zns->netlink_dplane_in.sock, F_SETFL, O_NONBLOCK) < 0) + zlog_err("Can't set %s socket error: %s(%d)", + zns->netlink_dplane_in.name, safe_strerror(errno), + errno); /* Set receive buffer size if it's set from command line */ if (nl_rcvbufsize) { netlink_recvbuf(&zns->netlink, nl_rcvbufsize); netlink_recvbuf(&zns->netlink_cmd, nl_rcvbufsize); - netlink_recvbuf(&zns->netlink_dplane, nl_rcvbufsize); + netlink_recvbuf(&zns->netlink_dplane_out, nl_rcvbufsize); + netlink_recvbuf(&zns->netlink_dplane_in, nl_rcvbufsize); } - netlink_install_filter(zns->netlink.sock, + /* Set filter for inbound sockets, to exclude events we've generated + * ourselves. + */ + netlink_install_filter(zns->netlink.sock, zns->netlink_cmd.snl.nl_pid, + zns->netlink_dplane_out.snl.nl_pid); + + netlink_install_filter(zns->netlink_dplane_in.sock, zns->netlink_cmd.snl.nl_pid, - zns->netlink_dplane.snl.nl_pid); + zns->netlink_dplane_out.snl.nl_pid); zns->t_netlink = NULL; @@ -1549,13 +1621,18 @@ void kernel_terminate(struct zebra_ns *zns, bool complete) zns->netlink_cmd.sock = -1; } + if (zns->netlink_dplane_in.sock >= 0) { + close(zns->netlink_dplane_in.sock); + zns->netlink_dplane_in.sock = -1; + } + /* During zebra shutdown, we need to leave the dataplane socket * around until all work is done. */ if (complete) { - if (zns->netlink_dplane.sock >= 0) { - close(zns->netlink_dplane.sock); - zns->netlink_dplane.sock = -1; + if (zns->netlink_dplane_out.sock >= 0) { + close(zns->netlink_dplane_out.sock); + zns->netlink_dplane_out.sock = -1; } } } diff --git a/zebra/kernel_socket.c b/zebra/kernel_socket.c index 5c060ac6f8..d9c69ceb6d 100644 --- a/zebra/kernel_socket.c +++ b/zebra/kernel_socket.c @@ -529,7 +529,7 @@ int ifm_read(struct if_msghdr *ifm) /* paranoia: sanity check structure */ if (ifm->ifm_msglen < sizeof(struct if_msghdr)) { flog_err(EC_ZEBRA_NETLINK_LENGTH_ERROR, - "ifm_read: ifm->ifm_msglen %d too short\n", + "ifm_read: ifm->ifm_msglen %d too short", ifm->ifm_msglen); return -1; } @@ -807,23 +807,17 @@ static void ifam_read_mesg(struct ifa_msghdr *ifm, union sockunion *addr, switch (sockunion_family(addr)) { case AF_INET: case AF_INET6: { - char buf[4][INET6_ADDRSTRLEN]; int masklen = (sockunion_family(addr) == AF_INET) ? ip_masklen(mask->sin.sin_addr) : ip6_masklen(mask->sin6.sin6_addr); zlog_debug( - "%s: ifindex %d, ifname %s, ifam_addrs {%s}, ifam_flags 0x%x, addr %s/%d broad %s dst %s gateway %s", + "%s: ifindex %d, ifname %s, ifam_addrs {%s}, ifam_flags 0x%x, addr %pSU/%d broad %pSU dst %pSU gateway %pSU", __func__, ifm->ifam_index, (ifnlen ? ifname : "(nil)"), rtatostr(ifm->ifam_addrs, fbuf, sizeof(fbuf)), - ifm->ifam_flags, - sockunion2str(addr, buf[0], sizeof(buf[0])), - masklen, - sockunion2str(brd, buf[1], sizeof(buf[1])), - sockunion2str(&dst, buf[2], sizeof(buf[2])), - sockunion2str(&gateway, buf[2], - sizeof(buf[2]))); + ifm->ifam_flags, addr, masklen, brd, &dst, + &gateway); } break; default: zlog_debug("%s: ifindex %d, ifname %s, ifam_addrs {%s}", @@ -951,7 +945,7 @@ static int rtm_read_mesg(struct rt_msghdr *rtm, union sockunion *dest, /* rt_msghdr version check. */ if (rtm->rtm_version != RTM_VERSION) flog_warn(EC_ZEBRA_RTM_VERSION_MISMATCH, - "Routing message version different %d should be %d.This may cause problem\n", + "Routing message version different %d should be %d.This may cause problem", rtm->rtm_version, RTM_VERSION); /* Be sure structure is cleared */ @@ -1463,6 +1457,14 @@ void kernel_terminate(struct zebra_ns *zns, bool complete) return; } +/* + * Called by the dplane pthread to read incoming OS messages and dispatch them. + */ +int kernel_dplane_read(struct zebra_dplane_info *info) +{ + return 0; +} + void kernel_update_multi(struct dplane_ctx_q *ctx_list) { struct zebra_dplane_ctx *ctx; diff --git a/zebra/rt.h b/zebra/rt.h index 929a44ade7..90148d2c0d 100644 --- a/zebra/rt.h +++ b/zebra/rt.h @@ -110,6 +110,11 @@ extern int kernel_del_mac_nhg(uint32_t nhg_id); */ extern void kernel_update_multi(struct dplane_ctx_q *ctx_list); +/* + * Called by the dplane pthread to read incoming OS messages and dispatch them. + */ +int kernel_dplane_read(struct zebra_dplane_info *info); + #ifdef __cplusplus } #endif diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index 39f865fbfc..ab06ea6438 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -37,11 +37,12 @@ #include "zebra/zebra_pbr.h" #include "printfrr.h" -/* Memory type for context blocks */ +/* Memory types */ DEFINE_MTYPE_STATIC(ZEBRA, DP_CTX, "Zebra DPlane Ctx"); DEFINE_MTYPE_STATIC(ZEBRA, DP_INTF, "Zebra DPlane Intf"); DEFINE_MTYPE_STATIC(ZEBRA, DP_PROV, "Zebra DPlane Provider"); DEFINE_MTYPE_STATIC(ZEBRA, DP_NETFILTER, "Zebra Netfilter Internal Object"); +DEFINE_MTYPE_STATIC(ZEBRA, DP_NS, "DPlane NSes"); #ifndef AOK # define AOK 0 @@ -402,6 +403,19 @@ struct zebra_dplane_provider { TAILQ_ENTRY(zebra_dplane_provider) dp_prov_link; }; +/* Declare types for list of zns info objects */ +PREDECL_DLIST(zns_info_list); + +struct dplane_zns_info { + struct zebra_dplane_info info; + + /* Read event */ + struct thread *t_read; + + /* List linkage */ + struct zns_info_list_item link; +}; + /* * Globals */ @@ -424,6 +438,9 @@ static struct zebra_dplane_globals { /* Ordered list of providers */ TAILQ_HEAD(zdg_prov_q, zebra_dplane_provider) dg_providers_q; + /* List of info about each zns */ + struct zns_info_list_head dg_zns_list; + /* Counter used to assign internal ids to providers */ uint32_t dg_provider_id; @@ -498,6 +515,9 @@ static struct zebra_dplane_globals { } zdplane_info; +/* Instantiate zns list type */ +DECLARE_DLIST(zns_info_list, struct dplane_zns_info, link); + /* * Lock and unlock for interactions with the zebra 'core' pthread */ @@ -690,6 +710,8 @@ static void dplane_ctx_free_internal(struct zebra_dplane_ctx *ctx) case DPLANE_OP_ADDR_INSTALL: case DPLANE_OP_ADDR_UNINSTALL: + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: /* Maybe free label string, if allocated */ if (ctx->u.intf.label != NULL && ctx->u.intf.label != ctx->u.intf.label_buf) { @@ -1011,6 +1033,12 @@ const char *dplane_op2str(enum dplane_op_e op) case DPLANE_OP_GRE_SET: ret = "GRE_SET"; break; + + case DPLANE_OP_INTF_ADDR_ADD: + return "INTF_ADDR_ADD"; + + case DPLANE_OP_INTF_ADDR_DEL: + return "INTF_ADDR_DEL"; } return ret; @@ -1108,6 +1136,21 @@ vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx) return ctx->zd_vrf_id; } +/* In some paths we have only a namespace id */ +void dplane_ctx_set_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t nsid) +{ + DPLANE_CTX_VALID(ctx); + + ctx->zd_ns_info.ns_id = nsid; +} + +ns_id_t dplane_ctx_get_ns_id(const struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + return ctx->zd_ns_info.ns_id; +} + bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -1154,6 +1197,13 @@ ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx) return ctx->zd_ifindex; } +void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex) +{ + DPLANE_CTX_VALID(ctx); + + ctx->zd_ifindex = ifindex; +} + void dplane_ctx_set_type(struct zebra_dplane_ctx *ctx, int type) { DPLANE_CTX_VALID(ctx); @@ -1669,6 +1719,13 @@ uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx) return ctx->u.intf.metric; } +void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.metric = metric; +} + /* Is interface addr p2p? */ bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx) { @@ -1691,6 +1748,27 @@ bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx) return (ctx->u.intf.flags & DPLANE_INTF_BROADCAST); } +void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.flags |= DPLANE_INTF_CONNECTED; +} + +void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.flags |= DPLANE_INTF_SECONDARY; +} + +void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx) +{ + DPLANE_CTX_VALID(ctx); + + ctx->u.intf.flags |= DPLANE_INTF_BROADCAST; +} + const struct prefix *dplane_ctx_get_intf_addr( const struct zebra_dplane_ctx *ctx) { @@ -1699,6 +1777,14 @@ const struct prefix *dplane_ctx_get_intf_addr( return &(ctx->u.intf.prefix); } +void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx, + const struct prefix *p) +{ + DPLANE_CTX_VALID(ctx); + + prefix_copy(&(ctx->u.intf.prefix), p); +} + bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx) { DPLANE_CTX_VALID(ctx); @@ -1711,10 +1797,15 @@ const struct prefix *dplane_ctx_get_intf_dest( { DPLANE_CTX_VALID(ctx); - if (ctx->u.intf.flags & DPLANE_INTF_HAS_DEST) - return &(ctx->u.intf.dest_prefix); - else - return NULL; + return &(ctx->u.intf.dest_prefix); +} + +void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx, + const struct prefix *p) +{ + DPLANE_CTX_VALID(ctx); + + prefix_copy(&(ctx->u.intf.dest_prefix), p); } bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx) @@ -1731,6 +1822,35 @@ const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx) return ctx->u.intf.label; } +void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label) +{ + size_t len; + + DPLANE_CTX_VALID(ctx); + + if (ctx->u.intf.label && ctx->u.intf.label != ctx->u.intf.label_buf) + free(ctx->u.intf.label); + + ctx->u.intf.label = NULL; + + if (label) { + ctx->u.intf.flags |= DPLANE_INTF_HAS_LABEL; + + /* Use embedded buffer if it's adequate; else allocate. */ + len = strlen(label); + + if (len < sizeof(ctx->u.intf.label_buf)) { + strlcpy(ctx->u.intf.label_buf, label, + sizeof(ctx->u.intf.label_buf)); + ctx->u.intf.label = ctx->u.intf.label_buf; + } else { + ctx->u.intf.label = strdup(label); + } + } else { + ctx->u.intf.flags &= ~DPLANE_INTF_HAS_LABEL; + } +} + /* Accessors for MAC information */ vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx) { @@ -2177,9 +2297,9 @@ static int dplane_ctx_ns_init(struct zebra_dplane_ctx *ctx, * two messages in some 'update' cases. */ if (is_update) - zns->netlink_dplane.seq += 2; + zns->netlink_dplane_out.seq += 2; else - zns->netlink_dplane.seq++; + zns->netlink_dplane_out.seq++; #endif /* HAVE_NETLINK */ return AOK; @@ -4709,10 +4829,92 @@ static void dplane_info_from_zns(struct zebra_dplane_info *ns_info, #if defined(HAVE_NETLINK) ns_info->is_cmd = true; - ns_info->nls = zns->netlink_dplane; + ns_info->nls = zns->netlink_dplane_out; #endif /* NETLINK */ } +#ifdef HAVE_NETLINK +/* + * Callback when an OS (netlink) incoming event read is ready. This runs + * in the dplane pthread. + */ +static int dplane_incoming_read(struct thread *event) +{ + struct dplane_zns_info *zi = THREAD_ARG(event); + + kernel_dplane_read(&zi->info); + + /* Re-start read task */ + thread_add_read(zdplane_info.dg_master, dplane_incoming_read, zi, + zi->info.nls.sock, &zi->t_read); + + return 0; +} +#endif /* HAVE_NETLINK */ + +/* + * Notify dplane when namespaces are enabled and disabled. The dplane + * needs to start and stop reading incoming events from the zns. In the + * common case where vrfs are _not_ namespaces, there will only be one + * of these. + * + * This is called in the main pthread. + */ +void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled) +{ + struct dplane_zns_info *zi; + + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("%s: %s for nsid %u", __func__, + (enabled ? "ENABLED" : "DISABLED"), zns->ns_id); + + /* Search for an existing zns info entry */ + frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) { + if (zi->info.ns_id == zns->ns_id) + break; + } + + if (enabled) { + /* Create a new entry if necessary; start reading. */ + if (zi == NULL) { + zi = XCALLOC(MTYPE_DP_NS, sizeof(*zi)); + + zi->info.ns_id = zns->ns_id; + + zns_info_list_add_tail(&zdplane_info.dg_zns_list, zi); + + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("%s: nsid %u, new zi %p", __func__, + zns->ns_id, zi); + } + + /* Make sure we're up-to-date with the zns object */ +#if defined(HAVE_NETLINK) + zi->info.is_cmd = false; + zi->info.nls = zns->netlink_dplane_in; + + /* Start read task for the dplane pthread. */ + if (zdplane_info.dg_master) + thread_add_read(zdplane_info.dg_master, + dplane_incoming_read, zi, + zi->info.nls.sock, &zi->t_read); +#endif + } else if (zi) { + if (IS_ZEBRA_DEBUG_DPLANE) + zlog_debug("%s: nsid %u, deleting zi %p", __func__, + zns->ns_id, zi); + + /* Stop reading, free memory */ + zns_info_list_del(&zdplane_info.dg_zns_list, zi); + + if (zdplane_info.dg_master) + thread_cancel_async(zdplane_info.dg_master, &zi->t_read, + NULL); + + XFREE(MTYPE_DP_NS, zi); + } +} + /* * Provider api to signal that work/events are available * for the dataplane pthread. @@ -4878,6 +5080,14 @@ static void kernel_dplane_log_detail(struct zebra_dplane_ctx *ctx) dplane_ctx_get_ifname(ctx), ctx->u.gre.link_ifindex); break; + + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: + zlog_debug("Dplane incoming op %s, intf %s, addr %pFX", + dplane_op2str(dplane_ctx_get_op(ctx)), + dplane_ctx_get_ifname(ctx), + dplane_ctx_get_intf_addr(ctx)); + break; } } @@ -5020,6 +5230,11 @@ static void kernel_dplane_handle_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_BR_PORT_UPDATE: break; + /* TODO -- error counters for incoming events? */ + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: + break; + case DPLANE_OP_NONE: if (res != ZEBRA_DPLANE_REQUEST_SUCCESS) atomic_fetch_add_explicit(&zdplane_info.dg_other_errors, @@ -5355,9 +5570,21 @@ done: */ static int dplane_check_shutdown_status(struct thread *event) { + struct dplane_zns_info *zi; + if (IS_ZEBRA_DEBUG_DPLANE) zlog_debug("Zebra dataplane shutdown status check called"); + /* Remove any zns info entries as we stop the dplane pthread. */ + frr_each_safe (zns_info_list, &zdplane_info.dg_zns_list, zi) { + zns_info_list_del(&zdplane_info.dg_zns_list, zi); + + if (zdplane_info.dg_master) + thread_cancel(&zi->t_read); + + XFREE(MTYPE_DP_NS, zi); + } + if (dplane_work_pending()) { /* Reschedule dplane check on a short timer */ thread_add_timer_msec(zdplane_info.dg_master, @@ -5652,6 +5879,7 @@ static void zebra_dplane_init_internal(void) TAILQ_INIT(&zdplane_info.dg_update_ctx_q); TAILQ_INIT(&zdplane_info.dg_providers_q); + zns_info_list_init(&zdplane_info.dg_zns_list); zdplane_info.dg_updates_per_cycle = DPLANE_DEFAULT_NEW_WORK; @@ -5667,6 +5895,7 @@ static void zebra_dplane_init_internal(void) */ void zebra_dplane_start(void) { + struct dplane_zns_info *zi; struct zebra_dplane_provider *prov; struct frr_pthread_attr pattr = { .start = frr_pthread_attr_default.start, @@ -5686,6 +5915,14 @@ void zebra_dplane_start(void) thread_add_event(zdplane_info.dg_master, dplane_thread_loop, NULL, 0, &zdplane_info.dg_t_update); + /* Enqueue reads if necessary */ + frr_each (zns_info_list, &zdplane_info.dg_zns_list, zi) { +#if defined(HAVE_NETLINK) + thread_add_read(zdplane_info.dg_master, dplane_incoming_read, + zi, zi->info.nls.sock, &zi->t_read); +#endif + } + /* Call start callbacks for registered providers */ DPLANE_LOCK(); diff --git a/zebra/zebra_dplane.h b/zebra/zebra_dplane.h index 3f3ff4de0f..a23de61c80 100644 --- a/zebra/zebra_dplane.h +++ b/zebra/zebra_dplane.h @@ -63,6 +63,12 @@ zebra_dplane_info_from_zns(struct zebra_dplane_info *zns_info, #endif /* NETLINK */ } +/* + * Notify dplane when namespaces are enabled and disabled. The dplane + * needs to start and stop reading incoming events from the ns. + */ +void zebra_dplane_ns_enable(struct zebra_ns *zns, bool enabled); + /* * Result codes used when returning status back to the main zebra context. */ @@ -98,7 +104,7 @@ enum zebra_dplane_result { */ /* - * Enqueue a route install or update for the dataplane. + * Operations that the dataplane can process. */ enum dplane_op_e { DPLANE_OP_NONE = 0, @@ -172,6 +178,10 @@ enum dplane_op_e { DPLANE_OP_NEIGH_TABLE_UPDATE, DPLANE_OP_GRE_SET, + + /* Incoming interface address events */ + DPLANE_OP_INTF_ADDR_ADD, + DPLANE_OP_INTF_ADDR_DEL, }; /* @@ -284,6 +294,7 @@ void dplane_ctx_set_dest(struct zebra_dplane_ctx *ctx, const char *dplane_ctx_get_ifname(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_ifname(struct zebra_dplane_ctx *ctx, const char *ifname); ifindex_t dplane_ctx_get_ifindex(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_ifindex(struct zebra_dplane_ctx *ctx, ifindex_t ifindex); /* Retrieve last/current provider id */ uint32_t dplane_ctx_get_provider(const struct zebra_dplane_ctx *ctx); @@ -306,6 +317,10 @@ uint32_t dplane_ctx_get_old_seq(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_vrf(struct zebra_dplane_ctx *ctx, vrf_id_t vrf); vrf_id_t dplane_ctx_get_vrf(const struct zebra_dplane_ctx *ctx); +/* In some paths we have only a namespace id */ +void dplane_ctx_set_ns_id(struct zebra_dplane_ctx *ctx, ns_id_t nsid); +ns_id_t dplane_ctx_get_ns_id(const struct zebra_dplane_ctx *ctx); + bool dplane_ctx_is_from_notif(const struct zebra_dplane_ctx *ctx); void dplane_ctx_set_notif_provider(struct zebra_dplane_ctx *ctx, uint32_t id); @@ -441,17 +456,26 @@ dplane_ctx_get_pw_backup_nhg(const struct zebra_dplane_ctx *ctx); /* Accessors for interface information */ uint32_t dplane_ctx_get_intf_metric(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_intf_metric(struct zebra_dplane_ctx *ctx, uint32_t metric); /* Is interface addr p2p? */ bool dplane_ctx_intf_is_connected(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_intf_set_connected(struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_is_secondary(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_intf_set_secondary(struct zebra_dplane_ctx *ctx); bool dplane_ctx_intf_is_broadcast(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_intf_set_broadcast(struct zebra_dplane_ctx *ctx); const struct prefix *dplane_ctx_get_intf_addr( const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_intf_addr(struct zebra_dplane_ctx *ctx, + const struct prefix *p); bool dplane_ctx_intf_has_dest(const struct zebra_dplane_ctx *ctx); const struct prefix *dplane_ctx_get_intf_dest( const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_intf_dest(struct zebra_dplane_ctx *ctx, + const struct prefix *p); bool dplane_ctx_intf_has_label(const struct zebra_dplane_ctx *ctx); const char *dplane_ctx_get_intf_label(const struct zebra_dplane_ctx *ctx); +void dplane_ctx_set_intf_label(struct zebra_dplane_ctx *ctx, const char *label); /* Accessors for MAC information */ vlanid_t dplane_ctx_mac_get_vlan(const struct zebra_dplane_ctx *ctx); diff --git a/zebra/zebra_fpm_netlink.c b/zebra/zebra_fpm_netlink.c index 68fb044353..168e36ac9b 100644 --- a/zebra/zebra_fpm_netlink.c +++ b/zebra/zebra_fpm_netlink.c @@ -281,7 +281,7 @@ static int netlink_route_info_fill(struct netlink_route_info *ri, int cmd, ri->af = rib_dest_af(dest); if (zvrf && zvrf->zns) - ri->nlmsg_pid = zvrf->zns->netlink_dplane.snl.nl_pid; + ri->nlmsg_pid = zvrf->zns->netlink_dplane_out.snl.nl_pid; ri->nlmsg_type = cmd; ri->rtm_table = table_info->table_id; diff --git a/zebra/zebra_nhg.c b/zebra/zebra_nhg.c index aed4f8ca8d..aa015992d5 100644 --- a/zebra/zebra_nhg.c +++ b/zebra/zebra_nhg.c @@ -2987,6 +2987,8 @@ void zebra_nhg_dplane_result(struct zebra_dplane_ctx *ctx) case DPLANE_OP_IPSET_ENTRY_DELETE: case DPLANE_OP_NEIGH_TABLE_UPDATE: case DPLANE_OP_GRE_SET: + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: break; } diff --git a/zebra/zebra_ns.c b/zebra/zebra_ns.c index 27b8a3ea47..8ae677fb22 100644 --- a/zebra/zebra_ns.c +++ b/zebra/zebra_ns.c @@ -123,6 +123,7 @@ int zebra_ns_enable(ns_id_t ns_id, void **info) zns->ns_id = ns_id; kernel_init(zns); + zebra_dplane_ns_enable(zns, true); interface_list(zns); route_read(zns); kernel_read_pbr_rules(zns); @@ -140,6 +141,8 @@ static int zebra_ns_disable_internal(struct zebra_ns *zns, bool complete) { route_table_finish(zns->if_table); + zebra_dplane_ns_enable(zns, false /*Disable*/); + kernel_terminate(zns, complete); table_manager_disable(zns->ns_id); diff --git a/zebra/zebra_ns.h b/zebra/zebra_ns.h index f7d1f40782..8237de7dde 100644 --- a/zebra/zebra_ns.h +++ b/zebra/zebra_ns.h @@ -52,7 +52,12 @@ struct zebra_ns { #ifdef HAVE_NETLINK struct nlsock netlink; /* kernel messages */ struct nlsock netlink_cmd; /* command channel */ - struct nlsock netlink_dplane; /* dataplane channel */ + + /* dplane system's channels: one for outgoing programming, + * for the FIB e.g., and one for incoming events from the OS. + */ + struct nlsock netlink_dplane_out; + struct nlsock netlink_dplane_in; struct thread *t_netlink; #endif diff --git a/zebra/zebra_rib.c b/zebra/zebra_rib.c index 1fb4e5e6fc..24c51e485f 100644 --- a/zebra/zebra_rib.c +++ b/zebra/zebra_rib.c @@ -4209,6 +4209,11 @@ static int rib_process_dplane_results(struct thread *thread) zebra_pbr_dplane_result(ctx); break; + case DPLANE_OP_INTF_ADDR_ADD: + case DPLANE_OP_INTF_ADDR_DEL: + zebra_if_addr_update_ctx(ctx); + break; + /* Some op codes not handled here */ case DPLANE_OP_ADDR_INSTALL: case DPLANE_OP_ADDR_UNINSTALL: