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; } } diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 4a15b7400496..d273e26a5dc2 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1891,6 +1891,36 @@ 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(bool fpm, struct nlmsghdr *n, + size_t nlen, const 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)) + 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 @@ -1909,10 +1939,13 @@ static inline bool _netlink_set_tag(struct nlmsghdr *n, unsigned int maxlen, * 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; @@ -2020,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; } @@ -2054,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) @@ -2149,34 +2189,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 * @@ -2431,12 +2443,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; @@ -2481,22 +2491,16 @@ 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)) + if (!_netlink_route_build_multipath(p, routedesc, + bytelen, + nexthop, + &req->n, + datalen, + &req->r, + &src1, tag, + fpm)) return 0; - /* - * Add encapsulation information when installing via - * FPM. - */ - if (fpm) { - if (!netlink_route_nexthop_encap( - &req->n, datalen, nexthop)) - return 0; - } - if (!setsrc && src1) { if (p->family == AF_INET) src.ipv4 = src1->ipv4;