FRR 开启EVPN功能

简介

frr使用advertise-all-vni命令开启bgp-evpn功能,配置如下所示:

router bgp 7675
 bgp router-id 192.168.59.128
 bgp bestpath as-path multipath-relax
 neighbor fabric peer-group
 neighbor fabric remote-as external
 neighbor 192.168.59.130 peer-group fabric
 !
 address-family l2vpn evpn
  neighbor fabric activate
  advertise-all-vni
 exit-address-family
!

该命令必须在l2vpn evpn地址族下配置。在多bgp实例的情况下,只有一个bgp实例能配置该命令,一般是默认bgp实例。

实现分析

DEFUN (bgp_evpn_advertise_all_vni,
       bgp_evpn_advertise_all_vni_cmd,
       "advertise-all-vni",
       "Advertise All local VNIs\n")
{
    struct bgp *bgp = VTY_GET_CONTEXT(bgp);
    struct bgp *bgp_evpn = NULL;

    if (!bgp)
        return CMD_WARNING;
    //获取已经设置了该命令的bgp实例。一般在创建默认bgp实例的时候会设置该值。
    bgp_evpn = bgp_get_evpn();
    //如果已经设置了evpn的bgp实例与当前bgp实例不一样,则说明当前bgp是一个vrf实例,不允许配置。
    //如果一定要配置的话,则使用no advertise-all-vni取消后在在指定的bgp实例下设置。
    if (bgp_evpn && bgp_evpn != bgp) {
        vty_out(vty, "%% Please unconfigure EVPN in VRF %s\n",
            bgp_evpn->name);
        return CMD_WARNING_CONFIG_FAILED;
    }
    /* 设置分发所有vni */
    evpn_set_advertise_all_vni(bgp);
    return CMD_SUCCESS;
}
/*
 * EVPN (VNI advertisement) enabled. Register with zebra.
 */
static void evpn_set_advertise_all_vni(struct bgp *bgp)
{
    bgp->advertise_all_vni = 1;
    //设置全局的evpn_bgp为当前的bgp
    bgp_set_evpn(bgp);
    //通知zebra获取vtep配置的所有vni
    bgp_zebra_advertise_all_vni(bgp, bgp->advertise_all_vni);
}
/* Sets the BGP instance where EVPN is enabled */
void bgp_set_evpn(struct bgp *bgp)
{
    if (bm->bgp_evpn == bgp)//相等,则直接退出
        return;

    /* First, release the reference count we hold on the instance */
    if (bm->bgp_evpn)
        bgp_unlock(bm->bgp_evpn);
    //设置新的bgp实例。
    bm->bgp_evpn = bgp;

    /* Increase the reference count on this new VRF */
    if (bm->bgp_evpn)
        bgp_lock(bm->bgp_evpn);
}
// 发送消息给zebra获取所有的vni。
int bgp_zebra_advertise_all_vni(struct bgp *bgp, int advertise)
{
    struct stream *s;

    /* Check socket. */
    if (!zclient || zclient->sock < 0)
        return 0;

    /* Don't try to register if Zebra doesn't know of this instance. */
    if (!IS_BGP_INST_KNOWN_TO_ZEBRA(bgp))
        return 0;

    s = zclient->obuf;
    stream_reset(s);
    //通知zebra进程获取所有已经配置的vni。
    zclient_create_header(s, ZEBRA_ADVERTISE_ALL_VNI, bgp->vrf_id);
    stream_putc(s, advertise);
    /* Also inform current BUM handling setting. This is really
     * relevant only when 'advertise' is set.
     */
    stream_putc(s, bgp->vxlan_flood_ctrl);
    stream_putw_at(s, 0, stream_get_endp(s));

    return zclient_send_message(zclient);
}

zebra对该命令的动作

//处理 evpn开启请求,该请求会将本地所有svi发送给bgp,以及每一个vxlan段下的fdb表,邻居表(精确主机路由)发送给bgp。
void zebra_vxlan_advertise_all_vni(ZAPI_HANDLER_ARGS)
{
    struct stream *s = NULL;
    int advertise = 0;
    enum vxlan_flood_control flood_ctrl;

    /* Mismatch between EVPN VRF and current VRF (should be prevented by
     * bgpd's cli) 
     * 判断EVPN VRF和当前vrf是否一致,不一致则退出。
     */
    if (is_evpn_enabled() && !EVPN_ENABLED(zvrf))
        return;

    s = msg;
    STREAM_GETC(s, advertise);
    STREAM_GETC(s, flood_ctrl);

    if (IS_ZEBRA_DEBUG_VXLAN)
        zlog_debug("EVPN VRF %s(%u) VNI Adv %s, currently %s, flood control %u",
               zvrf_name(zvrf), zvrf_id(zvrf),
               advertise ? "enabled" : "disabled",
               is_evpn_enabled() ? "enabled" : "disabled",
               flood_ctrl);
    //如果配置相等,则直接返回
    if (zvrf->advertise_all_vni == advertise)
        return;
    //设置新配置
    zvrf->advertise_all_vni = advertise;
    if (EVPN_ENABLED(zvrf)) {//新配置为使能
        zrouter.evpn_vrf = zvrf;//全局只有一个evpnvrf

        /* Note BUM handling bum流量处理 */
        zvrf->vxlan_flood_ctrl = flood_ctrl;

        /* Build VNI hash table and inform BGP. */
        zvni_build_hash_table();

        /* Add all SVI (L3 GW) MACs to BGP 添加所有l3svi,发送给bgp */
        hash_iterate(zvrf->vni_table, zvni_gw_macip_add_for_vni_hash,
                 NULL);

        /* Read the MAC FDB 读取fdb信息发送给bgp */
        macfdb_read(zvrf->zns);

        /* Read neighbors 读取邻居信息,发送给bgp */
        neigh_read(zvrf->zns);
    } else {
        /* Cleanup VTEPs for all VNIs - uninstall from
         * kernel and free entries.
         */
        hash_iterate(zvrf->vni_table, zvni_cleanup_all, zvrf);

        /* cleanup all l3vnis */
        hash_iterate(zrouter.l3vni_table, zl3vni_cleanup_all, NULL);

        /* Mark as "no EVPN VRF" */
        zrouter.evpn_vrf = NULL;
    }

stream_failure:
    return;
}

bgp处理zebra返回的消息

static int bgp_zebra_process_local_macip(ZAPI_CALLBACK_ARGS)
{
    struct stream *s;
    vni_t vni;
    struct bgp *bgp;
    struct ethaddr mac;
    struct ipaddr ip;
    int ipa_len;
    char buf[ETHER_ADDR_STRLEN];
    char buf1[INET6_ADDRSTRLEN];
    uint8_t flags = 0;
    uint32_t seqnum = 0;
    int state = 0;

    memset(&ip, 0, sizeof(ip));
    s = zclient->ibuf;
    vni = stream_getl(s);
    stream_get(&mac.octet, s, ETH_ALEN);
    ipa_len = stream_getl(s);
    if (ipa_len != 0 && ipa_len != IPV4_MAX_BYTELEN
        && ipa_len != IPV6_MAX_BYTELEN) {
        flog_err(EC_BGP_MACIP_LEN,
             "%u:Recv MACIP %s with invalid IP addr length %d",
             vrf_id, (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
             ipa_len);
        return -1;
    }

    if (ipa_len) {
        ip.ipa_type =
            (ipa_len == IPV4_MAX_BYTELEN) ? IPADDR_V4 : IPADDR_V6;
        stream_get(&ip.ip.addr, s, ipa_len);
    }
    if (cmd == ZEBRA_MACIP_ADD) {
        flags = stream_getc(s);
        seqnum = stream_getl(s);
    } else {
        state = stream_getl(s);
    }

    bgp = bgp_lookup_by_vrf_id(vrf_id);
    if (!bgp)
        return 0;

    if (BGP_DEBUG(zebra, ZEBRA))
        zlog_debug("%u:Recv MACIP %s flags 0x%x MAC %s IP %s VNI %u seq %u state %d",
               vrf_id, (cmd == ZEBRA_MACIP_ADD) ? "Add" : "Del",
               flags, prefix_mac2str(&mac, buf, sizeof(buf)),
               ipaddr2str(&ip, buf1, sizeof(buf1)), vni, seqnum,
               state);

    if (cmd == ZEBRA_MACIP_ADD)
        return bgp_evpn_local_macip_add(bgp, vni, &mac, &ip,
                        flags, seqnum);
    else
        return bgp_evpn_local_macip_del(bgp, vni, &mac, &ip, state);
}

/*
 * Handle add of a local MACIP.
 * 将本地mac/ip构建成type2 路由发送给remote
 */
int bgp_evpn_local_macip_add(struct bgp *bgp, vni_t vni, struct ethaddr *mac,
                 struct ipaddr *ip, uint8_t flags, uint32_t seq)
{
    struct bgpevpn *vpn;
    struct prefix_evpn p;

    /* Lookup VNI hash - should exist. */
    vpn = bgp_evpn_lookup_vni(bgp, vni);
    if (!vpn || !is_vni_live(vpn)) {
        flog_warn(EC_BGP_EVPN_VPN_VNI,
              "%u: VNI hash entry for VNI %u %s at MACIP ADD",
              bgp->vrf_id, vni, vpn ? "not live" : "not found");
        return -1;
    }

    /* Create EVPN type-2 route and schedule for processing. */
    build_evpn_type2_prefix(&p, mac, ip);
    if (update_evpn_route(bgp, vpn, &p, flags, seq)) {
        char buf[ETHER_ADDR_STRLEN];
        char buf2[INET6_ADDRSTRLEN];

        flog_err(
            EC_BGP_EVPN_ROUTE_CREATE,
            "%u:Failed to create Type-2 route, VNI %u %s MAC %s IP %s (flags: 0x%x)",
            bgp->vrf_id, vpn->vni,
            CHECK_FLAG(flags, ZEBRA_MACIP_TYPE_STICKY)
                ? "sticky gateway"
                : "",
            prefix_mac2str(mac, buf, sizeof(buf)),
            ipaddr2str(ip, buf2, sizeof(buf2)), flags);
        return -1;
    }

    return 0;
}

你可能感兴趣的