diff --git a/lib/nexthop.h b/lib/nexthop.h index c4e88dd844..9b71262589 100644 --- a/lib/nexthop.h +++ b/lib/nexthop.h @@ -25,6 +25,7 @@ #include "prefix.h" #include "mpls.h" +#include "vxlan.h" #ifdef __cplusplus extern "C" { @@ -60,6 +61,10 @@ enum blackhole_type { ? (type) \ : ((type) | 1) +enum nh_encap_type { + NET_VXLAN = 100, /* value copied from FPM_NH_ENCAP_VXLAN. */ +}; + /* Nexthop structure. */ struct nexthop { struct nexthop *next; @@ -123,6 +128,12 @@ struct nexthop { * only meaningful if the HAS_BACKUP flag is set. */ uint8_t backup_idx; + + /* Encapsulation information. */ + enum nh_encap_type nh_encap_type; + union { + vni_t vni; + } nh_encap; }; /* Backup index value is limited */ diff --git a/zebra/dplane_fpm_nl.c b/zebra/dplane_fpm_nl.c index 7d78b534f8..4b8948b71c 100644 --- a/zebra/dplane_fpm_nl.c +++ b/zebra/dplane_fpm_nl.c @@ -626,7 +626,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_ROUTE_UPDATE: case DPLANE_OP_ROUTE_DELETE: rv = netlink_route_multipath(RTM_DELROUTE, ctx, nl_buf, - sizeof(nl_buf)); + sizeof(nl_buf), true); if (rv <= 0) { zlog_debug("%s: netlink_route_multipath failed", __func__); @@ -643,7 +643,7 @@ static int fpm_nl_enqueue(struct fpm_nl_ctx *fnc, struct zebra_dplane_ctx *ctx) case DPLANE_OP_ROUTE_INSTALL: rv = netlink_route_multipath(RTM_NEWROUTE, ctx, &nl_buf[nl_buf_len], - sizeof(nl_buf) - nl_buf_len); + sizeof(nl_buf) - nl_buf_len, true); if (rv <= 0) { zlog_debug("%s: netlink_route_multipath failed", __func__); @@ -829,8 +829,8 @@ static void fpm_enqueue_rmac_table(struct hash_backet *backet, void *arg) dplane_ctx_reset(fra->ctx); dplane_ctx_set_op(fra->ctx, DPLANE_OP_MAC_INSTALL); dplane_mac_init(fra->ctx, fra->zl3vni->vxlan_if, - zif->brslave_info.br_if, vid, &zrmac->macaddr, - zrmac->fwd_info.r_vtep_ip, sticky); + zif->brslave_info.br_if, vid, + &zrmac->macaddr, zrmac->fwd_info.r_vtep_ip, sticky); if (fpm_nl_enqueue(fra->fnc, fra->ctx) == -1) { thread_add_timer(zrouter.master, fpm_rmac_send, fra->fnc, 1, &fra->fnc->t_rmacwalk); diff --git a/zebra/rt_netlink.c b/zebra/rt_netlink.c index 06da711303..7ca4425dc8 100644 --- a/zebra/rt_netlink.c +++ b/zebra/rt_netlink.c @@ -1528,11 +1528,28 @@ static bool nexthop_set_src(const struct nexthop *nexthop, int family, return false; } +static void netlink_route_nexthop_encap(struct nlmsghdr *n, size_t nlen, + struct nexthop *nh) +{ + struct rtattr *nest; + + switch (nh->nh_encap_type) { + case NET_VXLAN: + addattr_l(n, nlen, RTA_ENCAP_TYPE, &nh->nh_encap_type, + sizeof(uint16_t)); + + nest = addattr_nest(n, nlen, RTA_ENCAP); + addattr32(n, nlen, 0 /* VXLAN_VNI */, nh->nh_encap.vni); + addattr_nest_end(n, nest); + break; + } +} + /* * Routing table change via netlink interface, using a dataplane context object */ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, - uint8_t *data, size_t datalen) + uint8_t *data, size_t datalen, bool fpm) { int bytelen; struct nexthop *nexthop = NULL; @@ -1744,7 +1761,16 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, nexthop_num++; break; } + + /* + * Add encapsulation information when installing via + * FPM. + */ + if (fpm) + netlink_route_nexthop_encap(&req->n, datalen, + nexthop); } + if (setsrc) { if (p->family == AF_INET) addattr_l(&req->n, datalen, RTA_PREFSRC, @@ -1796,7 +1822,16 @@ ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, setsrc = 1; } } + + /* + * Add encapsulation information when installing via + * FPM. + */ + if (fpm) + netlink_route_nexthop_encap(&req->n, datalen, + nexthop); } + if (setsrc) { if (p->family == AF_INET) addattr_l(&req->n, datalen, RTA_PREFSRC, @@ -2149,7 +2184,8 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) if (RSYSTEM_ROUTE(dplane_ctx_get_type(ctx)) && !RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) { netlink_route_multipath(RTM_DELROUTE, ctx, - nl_pkt, sizeof(nl_pkt)); + nl_pkt, sizeof(nl_pkt), + false); netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt, dplane_ctx_get_ns(ctx), 0); @@ -2169,7 +2205,8 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) */ if (!RSYSTEM_ROUTE(dplane_ctx_get_old_type(ctx))) { netlink_route_multipath(RTM_DELROUTE, ctx, - nl_pkt, sizeof(nl_pkt)); + nl_pkt, sizeof(nl_pkt), + false); netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt, dplane_ctx_get_ns(ctx), 0); @@ -2182,7 +2219,8 @@ enum zebra_dplane_result kernel_route_update(struct zebra_dplane_ctx *ctx) } if (!RSYSTEM_ROUTE(dplane_ctx_get_type(ctx))) { - netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt)); + netlink_route_multipath(cmd, ctx, nl_pkt, sizeof(nl_pkt), + false); ret = netlink_talk_info(netlink_talk_filter, (struct nlmsghdr *)nl_pkt, dplane_ctx_get_ns(ctx), 0); diff --git a/zebra/rt_netlink.h b/zebra/rt_netlink.h index 15ef43c538..d6a993e78a 100644 --- a/zebra/rt_netlink.h +++ b/zebra/rt_netlink.h @@ -67,7 +67,8 @@ void rt_netlink_init(void); extern int netlink_mpls_multipath(int cmd, struct zebra_dplane_ctx *ctx); extern ssize_t netlink_route_multipath(int cmd, struct zebra_dplane_ctx *ctx, - uint8_t *data, size_t datalen); + uint8_t *data, size_t datalen, + bool fpm); extern ssize_t netlink_macfdb_update_ctx(struct zebra_dplane_ctx *ctx, uint8_t *data, size_t datalen); diff --git a/zebra/zebra_dplane.c b/zebra/zebra_dplane.c index e3eeecefc4..abbd136948 100644 --- a/zebra/zebra_dplane.c +++ b/zebra/zebra_dplane.c @@ -32,6 +32,7 @@ #include "zebra/zebra_memory.h" #include "zebra/zebra_router.h" #include "zebra/zebra_dplane.h" +#include "zebra/zebra_vxlan_private.h" #include "zebra/rt.h" #include "zebra/debug.h" @@ -178,7 +179,6 @@ struct dplane_mac_info { struct ethaddr mac; struct in_addr vtep_ip; bool is_sticky; - }; /* @@ -1535,6 +1535,7 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, struct zebra_ns *zns; struct zebra_vrf *zvrf; struct nexthop *nexthop; + zebra_l3vni_t *zl3vni; if (!ctx || !rn || !re) goto done; @@ -1584,10 +1585,24 @@ int dplane_ctx_route_init(struct zebra_dplane_ctx *ctx, enum dplane_op_e op, re->nhe->backup_info->nhe->nhg.nexthop, NULL); } - /* Ensure that the dplane nexthops' flags are clear. */ - for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) + /* + * Ensure that the dplane nexthops' flags are clear and copy + * encapsulation information. + */ + for (ALL_NEXTHOPS(ctx->u.rinfo.zd_ng, nexthop)) { UNSET_FLAG(nexthop->flags, NEXTHOP_FLAG_FIB); + /* Check for available encapsulations. */ + if (!CHECK_FLAG(re->flags, ZEBRA_FLAG_EVPN_ROUTE)) + continue; + + zl3vni = zl3vni_from_vrf(nexthop->vrf_id); + if (zl3vni && is_l3vni_oper_up(zl3vni)) { + nexthop->nh_encap_type = NET_VXLAN; + nexthop->nh_encap.vni = zl3vni->vni; + } + } + /* Don't need some info when capturing a system notification */ if (op == DPLANE_OP_SYS_ROUTE_ADD || op == DPLANE_OP_SYS_ROUTE_DELETE) {