当FRR得知配置了一个本地VNI时,如果用户没有明确为这个VNI配置RD和RT,FRR会自动为这个VNI导出RD和RTS(包括导入和导出)。推导规则如下:RD格式为“Type:Routerid:VNI-Index”RT格式为“AS:VNI”RD和RT在交换EVPN路由时会用到。RD用于区分不同VNI的EVPN路由(因为同一个mac地址可以存在于不同的VLAN中,同一个IP地址可以存在于不同的VRF中,所以这里的RD与VNI是一一对应的,即和我之前的OneL3VNIoneRD想的不一样)。RT用于描述路由的归属,即谁发布了这条路由,用于路由过滤。通过结合导入和导出RT过滤路由的导入和导出。(说白了,RT就像密码一样,路由器在发送路由时,携带了对应的导出RT,接收方收到路由后,检查RT是否与本地VNI对应的导入RT一致,如果是一致,接受它,否则拒绝)。VNI索引由路由器本地维护的ID分配器生成。在本地配置一个VNI后,会为该VNI分配一个索引。所以RD的作用只是分隔不同VNI之间的路由,没有其他意义,是一个本地ID。邻居路由器收到路由后不会分析RD的具体含义,而只是将其作为路由区分符号。取值范围0到65535。RD由8个字节组成:TYPE:RD类型,两个字节,现在有三个值:RD_TYPE_AS(两个字节的AS类型,Routerid字段填写AS号,该字段是否占用两个bytes,剩下的两个字节会填充其他字段,type值为0),RD_TYPE_IP(IP类型,RouterId字段填充RouterId,该字段为四个字节),RD_TYPE_AS4(四个字节AS类型,Routerid字段填写的是AS号,该字段是否占用4个字节,type值为2)。该字段在配置期间不可见,由系统填充。RouterId:路由器ID,四个字节,不同类型填写的内容不同。VNI-索引:两个字节。RT值由两部分组成,共6个字节,其中AS部分只占两个字节。即使使用AS4,这个字段也是两个字节,取AS4的低两个字节,VNI字段占四个字节。.不同VNI的全局唯一性由VNI字段保证。RT在EVPN扩展社区中发布路由时使用。RT字段保证不同的VNI有不同的RT,同时保证同一个自治区的同一个VNI有相同的RT。对于eBGPEVPN对等体,它们的AS是不同的。如果派生的RT用于路由导入,路由导入会失败。为了解决ebgp对等体导入相同VNI的路由问题。在实现FRR时,做了特殊处理:当收到邻居发来的EVPN路由时,首先检查路由中VNI对应的RT值是否为路由器中对应VNI的RT值,如果是,允许进口;如果不是,则使用“*:VNI”格式进行匹配(即通配符AS部分)。该方法只有在导出RT时才会生效。当用户手动配置RT时,将采用严格的匹配方式。RD和RTFRR的用户手动配置支持RD和RT的手动配置。address-familyl2vpnevpnadvertise-all-vnivni10200rd172.16.100.1:20route-targetimport65100:20上述配置中,缩进表示归属关系。从配置可以看出,RD和RT需要配置在对应的VNI下,而且必须配置在evpn地址族下。用户删除RD和RT后,系统会重新使用派生的RD和RT,就好像用户没有配置过一样。RD值和VNI值是一一对应的,一个VNI可以配置多个RT值。地址系列l2vpnevpnvni10400路由目标导入100:400路由目标导入100:500vni10500路由目标导入65000:500路由目标导出65000:500EVPNRD/**派生assRDed自动格式化*形式为RouterId:unique-id-for-vni。*自动为VNI派生一个RD,RD格式为RouterID:VNI-INDEX。*/voidbgp_evpn_derive_auto_rd(structbgp*bgp,structbgpevpn*vpn){charbuf[100];vpn->prd.family=AF_UNSPEC;vpn->prd.prefixlen=64;sprintf(buf,"%s:%hu",inet_ntoa(bgp->router_id),vpn->rd_id);(void)str2prefix_rd(buf,&vpn->prd);UNSET_FLAG(vpn->flags,VNI_FLAG_RD_CFGD);}intstr2prefix_rd(constchar*str,structprefix_rd*prd){intret;/*被调用函数的ret*/intlret;/*这个函数的本地ret*/char*p;字符*p2;结构流*s=NULL;字符*一半=NULL;in_addr地址;s=stream_new(8);prd->family=AF_UNSPEC;prd->prefixlen=64;lret=0;//先找冒号,冒号前是路由idp=strchr(str,':');如果(!p)跳出;//冒号后面是vni-index,必须全是数字。如果(!all_digit(p+1))跳出;一半=XMALLOC(MTYPE_TMP,(p-str)+1);memcpy(half,str,(p-str));half[p-str]='\0';//点分小数,找到第一个点。p2=strchr(str,'.');//非IP地址,可作为。evpn使用的IP地址。如果(!p2){无符号长as_val;如果(!all_digit(half))跳出;as_val=atol(一半);如果(as_val>0xffff){stream_putw(s,RD_TYPE_AS4);stream_putl(s,as_val);(s,atol(p+1));}else{stream_putw(s,RD_TYPE_AS);stream_putw(s,as_val);stream_putl(s,atol(p+1));}}else{//点分十进制转换为整数。ret=inet_aton(half,&addr);如果(!ret)退出;//设置RD类型为IP。哦,后面是IP地址,然后是两字节的vni-index。//RD一共有8个字节。stream_putw(s,RD_TYPE_IP);stream_put_in_addr(s,&addr);stream_putw(s,atol(p+1));}memcpy(prd->val,s->data,8);lret=1;out:if(s)stream_free(s);XFREE(MTYPE_TMP,一半);returnlret;}EVPNRT派生RT/**根据传递的信息自动创建RT扩展社区:*形式为AS:VNI。*注意:我们只使用AS的低16位。这已经足够*需要获得一个RT值,该值在不同*VNI之间是唯一的,但对于特定*VNI在路由器(在同一AS中)之间是相同的。*/staticvoidform_auto_rt(structbgp*bgp,vni_tvni,structlist*rtl){structecommunity_valeval;结构ecommunity*ecomadd;如果(bgp->advertise_autort_rfc8365)vni|=EVPN_AUTORT_VXLAN;encode_route_target_as((bgp->as&0xFFFF),vni,&eval);//创建一个新的扩展体ecomadd=ecommunity_new();//设置扩展团的值ecommunity_add_val(ecomadd,&eval);//将rt扩展社区添加到rt链表listnode_add_sort(rtl,ecomadd);}/**EncodeBGPRouteTargetAS:nn.*/staticinlinevoidencode_route_target_as(as_tas,uint32_tval,structeconomy_val*eval){eval->val[0]=ECOMMUNITY_ENCODE_AS;//扩展社区类型eval->val[1]=ECOMMUNITY_ROUTE_TARGET;//扩展社区子类型eval->val[2]=(as>>8)&0xff;//作为eval->val[3]=as&0xff;eval->val[4]=(val>>24)&0xff;//vnieval->val[5]=(val>>16)&0xff;eval->val[6]=(val>>8)&0xff;eval->val[7]=val&0xff;}/**将VNI的RT(配置的或自动派生的)映射到VNI。*映射将在路由处理期间使用。*将RTS映射到对应的VNI主要是importrt。这些rts在收到更新消息时进行路由过滤。*/voidbgp_evpn_map_vni_to_its_rts(structbgp*bgp,structbgpevpn*vpn){inti;结构ecommunity_val*eval;结构列表节点*node,*nnode;结构ecommunity*ecom;对于(ALL_LIST_ELEMENTS(vpn->import_rtl,node,nnode,ecom)){for(i=0;i
