From 084aba4ec06d2f9df31ce1e3964d5847bd618cee Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Fri, 3 May 2024 11:59:02 -0400 Subject: [PATCH 1/4] zebra: Add 2 things to fpm_listener 1) Add ability to hex-dump the received packet for debugging 2) Receive encap type and vxlan vni and display them. Signed-off-by: Donald Sharp --- zebra/fpm_listener.c | 117 +++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 112 insertions(+), 5 deletions(-) diff --git a/zebra/fpm_listener.c b/zebra/fpm_listener.c index 5533fa7f8be4..fed6c41631b4 100644 --- a/zebra/fpm_listener.c +++ b/zebra/fpm_listener.c @@ -31,6 +31,7 @@ #include #include +#include #include "rt_netlink.h" #include "fpm/fpm.h" @@ -42,6 +43,7 @@ struct glob { int server_sock; int sock; bool reflect; + bool dump_hex; }; struct glob glob_space; @@ -292,6 +294,8 @@ netlink_prot_to_s(unsigned char prot) struct netlink_nh { struct rtattr *gateway; int if_index; + uint16_t encap_type; + uint32_t vxlan_vni; }; struct netlink_msg_ctx { @@ -341,7 +345,7 @@ static inline void netlink_msg_ctx_set_err(struct netlink_msg_ctx *ctx, * parse_rtattrs_ */ static int parse_rtattrs_(struct rtattr *rta, size_t len, struct rtattr **rtas, - int num_rtas, const char **err_msg) + uint16_t num_rtas, const char **err_msg) { memset(rtas, 0, num_rtas * sizeof(rtas[0])); @@ -387,7 +391,8 @@ static int parse_rtattrs(struct netlink_msg_ctx *ctx, struct rtattr *rta, * netlink_msg_ctx_add_nh */ static int netlink_msg_ctx_add_nh(struct netlink_msg_ctx *ctx, int if_index, - struct rtattr *gateway) + struct rtattr *gateway, uint16_t encap_type, + uint32_t vxlan_vni) { struct netlink_nh *nh; @@ -400,6 +405,9 @@ static int netlink_msg_ctx_add_nh(struct netlink_msg_ctx *ctx, int if_index, nh->gateway = gateway; nh->if_index = if_index; + + nh->encap_type = encap_type; + nh->vxlan_vni = vxlan_vni; return 1; } @@ -412,6 +420,7 @@ static int parse_multipath_attr(struct netlink_msg_ctx *ctx, size_t len; struct rtnexthop *rtnh; struct rtattr *rtattrs[RTA_MAX + 1]; + struct rtattr *tb[RTA_MAX + 1]; struct rtattr *gateway; const char *err_msg; @@ -420,6 +429,8 @@ static int parse_multipath_attr(struct netlink_msg_ctx *ctx, for (; len > 0; len -= NLMSG_ALIGN(rtnh->rtnh_len), rtnh = RTNH_NEXT(rtnh)) { + uint32_t vxlan_vni; + uint16_t encap_type; if (!RTNH_OK(rtnh, len)) { netlink_msg_ctx_set_err(ctx, "Malformed nh"); @@ -443,7 +454,27 @@ static int parse_multipath_attr(struct netlink_msg_ctx *ctx, } gateway = rtattrs[RTA_GATEWAY]; - netlink_msg_ctx_add_nh(ctx, rtnh->rtnh_ifindex, gateway); + memset(tb, 0, sizeof(tb)); + if (rtattrs[RTA_ENCAP]) { + parse_rtattrs_(RTA_DATA(rtattrs[RTA_ENCAP]), + rtattrs[RTA_ENCAP]->rta_len - + sizeof(struct rtattr), + tb, ARRAY_SIZE(tb), &err_msg); + } + + if (rtattrs[RTA_ENCAP_TYPE]) + encap_type = + *(uint16_t *)RTA_DATA(rtattrs[RTA_ENCAP_TYPE]); + else + encap_type = 0; + + if (tb[0]) + vxlan_vni = *(uint32_t *)RTA_DATA(tb[0]); + else + vxlan_vni = 0; + + netlink_msg_ctx_add_nh(ctx, rtnh->rtnh_ifindex, gateway, + encap_type, vxlan_vni); } return 1; @@ -485,11 +516,33 @@ static int parse_route_msg(struct netlink_msg_ctx *ctx) gateway = rtattrs[RTA_GATEWAY]; oif = rtattrs[RTA_OIF]; if (gateway || oif) { + struct rtattr *tb[RTA_MAX + 1] = { 0 }; + uint16_t encap_type = 0; + uint32_t vxlan_vni = 0; + if_index = 0; if (oif) if_index = *((int *)RTA_DATA(oif)); - netlink_msg_ctx_add_nh(ctx, if_index, gateway); + + if (rtattrs[RTA_ENCAP]) { + const char *err_msg; + + parse_rtattrs_(RTA_DATA(rtattrs[RTA_ENCAP]), + rtattrs[RTA_ENCAP]->rta_len - + sizeof(struct rtattr), + tb, ARRAY_SIZE(tb), &err_msg); + } + + if (rtattrs[RTA_ENCAP_TYPE]) + encap_type = + *(uint16_t *)RTA_DATA(rtattrs[RTA_ENCAP_TYPE]); + + if (tb[0]) + vxlan_vni = *(uint32_t *)RTA_DATA(tb[0]); + + netlink_msg_ctx_add_nh(ctx, if_index, gateway, encap_type, + vxlan_vni); } rtattr = rtattrs[RTA_MULTIPATH]; @@ -557,6 +610,11 @@ static int netlink_msg_ctx_snprint(struct netlink_msg_ctx *ctx, char *buf, cur += snprintf(cur, end - cur, " via interface %d", nh->if_index); } + + if (nh->encap_type) + cur += snprintf(cur, end - cur, + ", Encap Type: %u Vxlan vni %u", + nh->encap_type, nh->vxlan_vni); } return cur - buf; @@ -573,6 +631,51 @@ static void print_netlink_msg_ctx(struct netlink_msg_ctx *ctx) printf("%s\n", buf); } +static void fpm_listener_hexdump(const void *mem, size_t len) +{ + char line[64]; + const uint8_t *src = mem; + const uint8_t *end = src + len; + + if (!glob->dump_hex) + return; + + if (len == 0) { + printf("%016lx: (zero length / no data)\n", (long)src); + return; + } + + while (src < end) { + struct fbuf fb = { + .buf = line, + .pos = line, + .len = sizeof(line), + }; + const uint8_t *lineend = src + 8; + uint32_t line_bytes = 0; + + printf("%016lx: ", (long)src); + + while (src < lineend && src < end) { + printf("%02x ", *src++); + line_bytes++; + } + if (line_bytes < 8) + printf("%*s", (8 - line_bytes) * 3, ""); + + src -= line_bytes; + while (src < lineend && src < end && fb.pos < fb.buf + fb.len) { + uint8_t byte = *src++; + + if (isprint(byte)) + *fb.pos++ = byte; + else + *fb.pos++ = '.'; + } + printf("\n"); + } +} + /* * parse_netlink_msg */ @@ -582,6 +685,7 @@ static void parse_netlink_msg(char *buf, size_t buf_len, fpm_msg_hdr_t *fpm) struct nlmsghdr *hdr; unsigned int len; + fpm_listener_hexdump(buf, buf_len); ctx = &ctx_space; hdr = (struct nlmsghdr *)buf; @@ -667,7 +771,7 @@ int main(int argc, char **argv) memset(glob, 0, sizeof(*glob)); - while ((r = getopt(argc, argv, "rd")) != -1) { + while ((r = getopt(argc, argv, "rdv")) != -1) { switch (r) { case 'r': glob->reflect = true; @@ -675,6 +779,9 @@ int main(int argc, char **argv) case 'd': fork_daemon = true; break; + case 'v': + glob->dump_hex = true; + break; } } From ba5a3538e8b7198ac58e97c1cc6e65f7763359b2 Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 8 May 2024 12:46:08 -0400 Subject: [PATCH 2/4] zebra: Move netlink_route_nexthop_encap Move this static function earlier so we can avoid a predecleartion. Signed-off-by: Donald Sharp --- zebra/rt_netlink.c | 55 +++++++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 28 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 4a15b7400496..745f6497fb2b 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1891,6 +1891,33 @@ static inline bool _netlink_set_tag(struct nlmsghdr *n, unsigned int maxlen, return true; } +/* + * The function returns true if the attribute could be added + * to the message, otherwise false is returned. + */ +static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, + struct nexthop *nh) +{ + struct rtattr *nest; + + switch (nh->nh_encap_type) { + case NET_VXLAN: + if (!nl_attr_put16(n, nlen, RTA_ENCAP_TYPE, nh->nh_encap_type)) + return false; + + nest = nl_attr_nest(n, nlen, RTA_ENCAP); + if (!nest) + return false; + + if (!nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */, nh->nh_encap.vni)) + return false; + nl_attr_nest_end(n, nest); + break; + } + + return true; +} + /* This function takes a nexthop as argument and * appends to the given netlink msg. If the nexthop * defines a preferred source, the src parameter @@ -2149,34 +2176,6 @@ static bool nexthop_set_src(const struct nexthop *nexthop, int family, return false; } -/* - * The function returns true if the attribute could be added - * to the message, otherwise false is returned. - */ -static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, - struct nexthop *nh) -{ - struct rtattr *nest; - - switch (nh->nh_encap_type) { - case NET_VXLAN: - if (!nl_attr_put16(n, nlen, RTA_ENCAP_TYPE, nh->nh_encap_type)) - return false; - - nest = nl_attr_nest(n, nlen, RTA_ENCAP); - if (!nest) - return false; - - if (!nl_attr_put32(n, nlen, 0 /* VXLAN_VNI */, - nh->nh_encap.vni)) - return false; - nl_attr_nest_end(n, nest); - break; - } - - return true; -} - /* * Routing table change via netlink interface, using a dataplane context object * From 569f9e439418a06ac0ddf9b68cd1943cbf860d1d Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 8 May 2024 12:48:12 -0400 Subject: [PATCH 3/4] zebra: Move fpm check to inside of netlink_route_nexthop_encap Signed-off-by: Donald Sharp --- zebra/rt_netlink.c | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 745f6497fb2b..9ac4bb9bf8bb 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1895,11 +1895,14 @@ static inline bool _netlink_set_tag(struct nlmsghdr *n, unsigned int maxlen, * The function returns true if the attribute could be added * to the message, otherwise false is returned. */ -static int netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, - struct nexthop *nh) +static int netlink_route_nexthop_encap(bool fpm, struct nlmsghdr *n, + size_t nlen, struct nexthop *nh) { struct rtattr *nest; + if (!fpm) + return true; + switch (nh->nh_encap_type) { case NET_VXLAN: if (!nl_attr_put16(n, nlen, RTA_ENCAP_TYPE, nh->nh_encap_type)) @@ -2430,12 +2433,10 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx * Add encapsulation information when * installing via FPM. */ - if (fpm) { - if (!netlink_route_nexthop_encap(&req->n, - datalen, - nexthop)) - return 0; - } + if (!netlink_route_nexthop_encap(fpm, &req->n, + datalen, + nexthop)) + return 0; nexthop_num++; break; @@ -2490,11 +2491,10 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx * Add encapsulation information when installing via * FPM. */ - if (fpm) { - if (!netlink_route_nexthop_encap( - &req->n, datalen, nexthop)) - return 0; - } + if (!netlink_route_nexthop_encap(fpm, &req->n, + datalen, + nexthop)) + return 0; if (!setsrc && src1) { if (p->family == AF_INET) From bd4fca132abd47d1ba08eca5e5193c431f095f7a Mon Sep 17 00:00:00 2001 From: Donald Sharp Date: Wed, 8 May 2024 12:52:12 -0400 Subject: [PATCH 4/4] zebra: Ensure multipath encodes vxlan right for fpm usage The fpm code path for the dplane_fpm_nl module was improperly encoding the multipath nexthop data for vxlan type routes. Move this into the embedded nexthop encoding where it belongs. This change makes it so that the usage of `-M dplane_fpm_nl` is now producing the same netlink messages that `-M fpm` produces when using vxlan based nexthops. Signed-off-by: Donald Sharp --- zebra/rt_netlink.c | 43 ++++++++++++++++++++++++------------------- 1 file changed, 24 insertions(+), 19 deletions(-) diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 9ac4bb9bf8bb..d273e26a5dc2 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1896,7 +1896,7 @@ static inline bool _netlink_set_tag(struct nlmsghdr *n, unsigned int maxlen, * to the message, otherwise false is returned. */ static int netlink_route_nexthop_encap(bool fpm, struct nlmsghdr *n, - size_t nlen, struct nexthop *nh) + size_t nlen, const struct nexthop *nh) { struct rtattr *nest; @@ -1939,10 +1939,13 @@ static int netlink_route_nexthop_encap(bool fpm, struct nlmsghdr *n, * The function returns true if the nexthop could be added * to the message, otherwise false is returned. */ -static bool _netlink_route_build_multipath( - const struct prefix *p, const char *routedesc, int bytelen, - const struct nexthop *nexthop, struct nlmsghdr *nlmsg, size_t req_size, - struct rtmsg *rtmsg, const union g_addr **src, route_tag_t tag) +static bool _netlink_route_build_multipath(const struct prefix *p, + const char *routedesc, int bytelen, + const struct nexthop *nexthop, + struct nlmsghdr *nlmsg, + size_t req_size, struct rtmsg *rtmsg, + const union g_addr **src, + route_tag_t tag, bool fpm) { char label_buf[256]; struct vrf *vrf; @@ -2050,6 +2053,13 @@ static bool _netlink_route_build_multipath( if (!_netlink_set_tag(nlmsg, req_size, tag)) return false; + /* + * Add encapsulation information when installing via + * FPM. + */ + if (!netlink_route_nexthop_encap(fpm, nlmsg, req_size, nexthop)) + return false; + nl_attr_rtnh_end(nlmsg, rtnh); return true; } @@ -2084,7 +2094,7 @@ _netlink_mpls_build_multipath(const struct prefix *p, const char *routedesc, bytelen = (family == AF_INET ? 4 : 16); return _netlink_route_build_multipath(p, routedesc, bytelen, nhlfe->nexthop, nlmsg, req_size, - rtmsg, src, 0); + rtmsg, src, 0, false); } static void _netlink_mpls_debug(int cmd, uint32_t label, const char *routedesc) @@ -2481,19 +2491,14 @@ ssize_t netlink_route_multipath_msg_encode(int cmd, struct zebra_dplane_ctx *ctx : "multipath"; nexthop_num++; - if (!_netlink_route_build_multipath( - p, routedesc, bytelen, nexthop, - &req->n, datalen, &req->r, &src1, - tag)) - return 0; - - /* - * Add encapsulation information when installing via - * FPM. - */ - if (!netlink_route_nexthop_encap(fpm, &req->n, - datalen, - nexthop)) + if (!_netlink_route_build_multipath(p, routedesc, + bytelen, + nexthop, + &req->n, + datalen, + &req->r, + &src1, tag, + fpm)) return 0; if (!setsrc && src1) {