简介
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;
}
**粗体** _斜体_ [链接](http://example.com) `代码` - 列表 > 引用
。你还可以使用@
来通知其他用户。