TMw6
zoB3{bGA!VUyB=*0Hq4QNg5pxkW#jukV7P~^mCV^A9vM<_6nz%~fn3B6N~@!)^QBYmTu)nXjXa*O=NJK45pS^{&O)gZ
z8jvLT2;T1-Rr?L5PBJ@6h_GA>1s;m`t^Pn-_p+R;vI+}t9y$@bp?Jv
z$syxRXKd-^`LP{P;p84(Tl2o|4a06X*8U_x^v}^i4h9x2uUe`1U0X>>$rSkdHxL^P
zD5X7TP|X36=)d8Z${)7YCq=#togWmJzkHplfdGD201!ddM@Ttd_alfCep89$dx73t
zt`vZTVh^YuPSG0Da)_+OB_t&D#pQ4)n5xhf3<46i)?g42=pr}4^mY(4+~V}frKWBG
zB>nO6vAlBu-ahg-M;w9AKB~lccT*e@-`(!V#*i1x>Lkk&lJsUE!A7Mi%r#}
zO1D#LXlSsEBr+O@EI&v*kZ-#TEWGOXh3BpT(a1tvV~p}5R)xQ9T5fT@EN^XTxp@Z(
zi6cLFXASKg_Eiwj68u(Uwes*gOE}aj85wcMql{@HGc;CODTi|9+M8XFS^`Da(t>
z!5C~6BqE4~%HXNol#3)(a3Dez_$8bVNTi|g3iJKXmk1z&4s&Y_o2{KiGc3=@TjNXEnPC2_)uYNw
z`VQ=GqIrx4D!w9+^sQaQ2__+o;HO|9_8+6;V2&way6-lj*CnB<{P{t`P@=D{n(7W3v3uT)W5C#B9{BUwLi2|fvv--vytAi01{Z-T}O{Wf7KhK@ga9W9gm>(
z4E=D8FW0Cbk1m-{Chw36kbJRc;?<)CNI~n0Gy+|qby&T=|7x!FPQu>zuml;LOTN`O
zqDbllHfW%vZ>$=ypj5E+0va4SfnO5K@04N-Y&xrdB2@xn0+>a`D
zpFx2Is_1Bj8|QfDdB)7-yh3P6wxF(I(a~03d&XqXTVjYAyOwgqS|YDkd)*9TXb1u<
zDbE>#PkFXA(=-Dg4T6mW+)%`c4$I?47G)-^R*Jg71QO8L)y|veMa9Y(8Un*P@|DNl
z)*%v>+k({e7=Fu3$IMV|9=zHo!?7x+ZMQIn@>E1Ym71!F*XAY*^X3*|UE>H}KPsrI
zllZzsMLQ!fx+34-rm1Fg>=c}oRiF{3)U27EDSv1R;Y9kmjwtlqxf}=_@Cx8$z3w1m
zZ@gfp>9}E}hm66t4=kWbQE)%5!)t2-;v#!pL9#cO@C6CYI7eE?F!1%mVi&pUcopYe>R@1$1~deoZY+l(|n)J
zVuQNJLf{R&AdA|{7>I(8Xa{9htZ~Z5x#Qz3)5vOI&zn7?e5f~L)_I44U(FuqW6
zx_sMk5v3^Sss7&nVLK@lfA$kTxXh36$uAi&AwG8H-`E{XUrnmY1^HvNWb-CK1&ZtQ
zw2;e;v*3o-`Px8ic+|RuNXw(izk`{XtXh{kFPSP!=J+K%){2B|4c6
z-VB09+skj+q<6*~)IS=oUZYjVUDcI6?Ty5ZGrkF#ki`C)qVZ@s3dM5ebVZEXP(3W{
zoSi+nSoPA<70!ijv@0fgHL_|f_UBHapvazs$bGh)sA+5POL6{PYJL{AH*S(?@$F-*
zcN_B2r#^o{NmfuF*>{nR9J-9HYJ5I*&+FP^XHA<=FR*NdLFeKcoZe;Rj
zy>}+Fx&E6WBo#0So>}Qh5_1`QF|M*rv~c}Ih@2T6q&K8CDqkQJSGR;-$nXIBS3tgL
zx+bbSK3uIh)qne*8=I7cd#p%_`VNS2qcr*pOvro>tb2UDX@eXrE0VnBWX>!4qATFX
zpaaS8hae!RhK!dKn4vdRS>d9w(`_cLdgPEjsRyfMG{W7QfcB1}*)ZuCS
z!(Lgr;1b!b;Nd6dT~f2?hcs8PBtM+Q1SEP1K=EF}IwOe{jNA1pp>Z3txD{$@2
z#Ad+}(TA?zRIx
zB8R#P!o|X(BDd|lf#H|0bPua;2-l9+7?;znCR}Hme9t#h?ahv#Ssa~Ue~x0W1Tw^@
z_{sq}dapmVXr9~EzQ3gN*6K|=q91SoatQRXnjG(F6vp=S6raE1{?v_uyb|v-D%xMo#Ui6@TI(H|<{Z{opuql}Yw`Okd?g(?f?oXnJGnNxpsGM@D
z|7>}h%3j)Ow)cJY-rey2-qBjy?X(O=L|t{epWNCVRLAAG^V-;W<=NM(r?KKt=U)6+
z2Nd>3agGp3TB%BsN&YXDb6W1c1|1|gTw79Iy1TBoE6(Q+hvf)cx~@A6!7zvP!J!g(
z(I1crVr)tPRdGaH+ks8L2_Vgj!E};@iP^HG
zT_u<%{n`D>`L-k>Cr95!>WcmZj$P!W)yd+i-*~(}Y_168I3i`jV}#brWuxzFZ?PIu
z#);om=iOp7j#YBWRpa3buhwo)F)kZXhTRqsK4dKn{Hnqq1j>DKx7l9~C~&FnoothG
z)Enf1lCZ2@6O)sE02@PwA}TJdT&k9v)9slE*PKFv>pAw~q%_wOI(|L42&VaG&vtYC
zX}Gmu%^d6L#mnMlD}KE7z}f#{EUeJ*LWt>g@1aGy^{@^<%X}kj&%ZoJe}3fZ>^L%g
z=)RTr`5nhDHJ>t{8HF5f>no4R!~Jo=k}36r*QL7!`v%w5%Xuw7MCNeg_7qh1ePHMX
zp0cL07t{)`OMtn}xdADzuuM~Qcvhx89fmN6S)vWJ8|A)@w#ZCe^=;wIko&0?NAY2$
zHaHwyf9nm}gS*=WWn7&7ZuWktNas?+J5BphA(1lt>t;!zm4Ng9=Z!H}W_3+-n8h{+
zri0fVQHQk)h^vIb1RX#sj+OUCycB13$wH*
zdB@3%YlR7yJ>Ro*jj&OeGGQ47h=b2ELYkhq58Cc9jT-P_%~Au+qk6lkQ(@g#C(EjV|%qXR4{G@=L`lX49xu8H>{qedz
z*lGM4-Usy6A2c#00SNflaBv;c`j=qcNiX|MOgO*~c5bdVQ|)84P4Set&GMYz-#aA9;fa)*RMEO0O|un|cmeKg}L-`%J`
z_@b^Es>7W}XPw08uCzoGDto&@;Tq*QM|e42c~Z)+?nMQ`VClj^_hOW#yEa>{@v|&<
z=;9uWOp5RDmvQ#}>F$L&Deg=yY+z0OVXNnp+^Y@vqE$1>-dN^o;_ifNKbHd*Rb)>6
zbtJ_2MYXptYm?6K+U?clyweHuo@+UhcxBJm4Lt9fVF&6(X%GoI(rv)(Y@wV5y)sMLTHbgfbMDp9jECNTXq6$YE?
zlC`CvG?BRM%il2j6h3kL?mE*D665rq2*8H=<+eLFIT_pdZUkX1ATRs1X&vivm$l-)
zqj7Jg!89XOF~7#+guaH`<&y6xVcGpO`*GHN{JwOFKl>)`Q^eQHncXa}16pwo@e~c9
zso;C^T)_?~=CVb!)wFx&X_*2UhXI%ItkhhdO3$y0)rij%x0hDIxb5}r)uh^A+#r3)n;%OT+GSTJo?8f$dv(A{l1ZnMlLXGXE;ZRn
zIdGRU;Tb~~916!oM@{~jM7nyfZaeGcJ=H6XsOihsw2nGg^vv65KTVMs<)AuX7nT!{
zg2KE+x8c5#a2ZMyUP;szc)nW6{RmjM5hpNbuJIb%!@BFvx9)k=%7O87pC8r5gqSOc
z<&+nPwt9UK4Vj`wfg*n+wPbuQXLl$2o556S-
zl&jr_CdMT}TH;|wz%BMh*s?RZ--7+=dXdH-Z%z7BK}@8UCV=qh6h6n_3Ael@q%MgpXkn8l!@msmo_^X80Febib%uVi`;p4!#l?z@fdb@qAt|
zpEB)edY`KEaU}LYm#!^wkv36?V{rS6`P!3s*EtXxLTC#2YS4Vh3(To~w%FT41ryGw
zLzJD2>hv()_@W*bAgF1?sN%60K$HPZ4&Dt7Mv99m`E{1IdWK*FasC_dIq>PvC}6^T
zNEn}?$@lwph^ibCw|}hzz7}qdylo}AZRMrSfC6<2uu)OlsYxTrLZbK{@big@e6`O7
z3;{r$p*k56hsD6a_mYWU-f^CCB}iB-Hy~NJ-G4SgEY2bR
zApETLKimG^{@3@R5|~7rflYzW8W#;6;$y!6zcbKir9v0tX*pux2GS>7SpUMihYU>-?Qp1^mFIm|o90jQl%C-b|SZXvXx(W|Ub{z76o(
z#AN;f7#AzW0k`V!KY{{2Oy)|{pkD1ZBHyc#2?-GIsokbzGbgEhc{
zydjQ{I}~Jop;xxvfZs8)joffq3%g=ZE&`v*PyxD*5}FbRSjkriQedDrI|5vWCsAdV
zUC^A0-kYc5_2oO!;Vc*pO-I0oCmFFI#>gZ&qyjFW50nv=bwGDWz}rsK!PiHJ->)rv
z;JSc5yW8xz-wmA>6caJ}lmSNpJ^&1pXs@U}(0@K8=({#=*9>`zEC(cEG+OEc%LJf)
zunaUgNXiJHi-YkJ^eAf3Cg^=c~pGs84qu!cTe_^bo-4<*-zB3tkSUXC2orbf2=
z)=88IU}sdIF$gw7@NA}QhVtNe7$;iS$s7Jlginy~qu`6U;CXTGuJV0zC4A?!*H$Hp
zgoj^8USe`2Q#o9ONKoinAw5pr-(6(o5L@)}zW0gFE1$5Kvla8e?8uyb`90ZQ%^EH4Y7nntl%0bd3pMXlH$FUe)Dp2p`Km?&l)@
z<-*EBC>YOQ3BL?
z(GRa`OA6kJ4%M6Lf|rVv_4{reP()zMR$wVi9dW`C9yQ%u6&@Y*f%eDsBb^B5-PII{
zlkzV-FFcGYK|2!l3kcPKFluwRG^0Ezt_FE1*fPvI3CKC106~KU%5?R&=0S{b@0zKQ
zwe2?B1}jwPLG60x`sd#dBRmTv)Z&mPUZY=>!BkMFy9~j6H+Q<6?%87!MMRT=QyVGd
z3h5wsTtH9ZmKTJ70-Fg;x{o+7Jvir|j)TH3aah_haf%m(aKJNJaOK{Kk`#Qs-(iJe
z&-x*%az7XiFD|}K&y29W^7C4Jf_d&F!hd&^r^WC%x#59SimNA>W9OIj_oIo(I`Te||EyN%o^?r4&;gO#V(j8b=S5}r3d8;KVVpQ@~S
z6x(%5U&4Zc7m7kzvYHg1FPe8$8FrAy3l(b|RVv0gR4`lB=oZPTZjNC>k+FJ3JF;)N
zCM1k`OkbK=uin_37yZc9WN+E#tX^T8M5@J-{NQJKh|224Q+)JETU<0?OV|hMmzY!6
z4N+hh>oNYYCxw~!`UYApYu|AYm!ct$REdxq)w2yDZr#=LQT=nhDVhGs*inR7N>?vR
z?nT8hGdyGk6et==oWg)sD9a!kUVRd!cJ|L~C5@C=)flFVy*S4oQuu8W+?}N+%XzH4
z$%-|BEYavjx&GfFdlK`E|D&=q4~MdC|M*zSKK9*U%o2$#*(S0tV<|!s(IDB^A(E}3
zVeDgQETIgcvTvc1B?-|;h!C2d2_c!3?Y%v}<9+}C&3`k;ocCP!bzIkZe!l1TKIZCg
zA)46mo1)00BAuH|f;kEm=1oktq=32mP{}MMdcBre5!T{Bg=)B2U$E$)VI1D|&f&z1vn)i))Wp22Xx>5`{CX48->d1ckkF3bUD-RlOU+z5RU*na`zR_lb
z>S5sFRA|lB82x3;sqH*Vl*wDKcWKu!xta9`e6Sx)7%%GFuBl~UE!R7RnVe>k?h~L>
zT9jS6KS-zw8vjIn=2tgTn}MoaN-Rhs6NLJHxc`$2K!PL{LwHZncte0eF!@wQQR-t#
zud6)m;Sw`aJ)WuC2Xwo${FYbxgE@IKDlj)abJ?q=#i?KHsRfVb@v!VdY`sKiL`5Ou
zZFzr?vI~`;VRnNs7AQ=p1}{UU%o!s&gOZ`Zac9v>V2(JMug?Wed_6P&b_veIIF)iT
ze<@z8XJ?L-&q=o+Vug%R4|UCl_XqQ^WIy1fPTam`10fgN{tF+~(Y0Ji6sXzB1S9Xb
z6~YODpmTnG0}5tTsK0Keu6baL9g&f^2b9w`RS^SZv{&>BHiT@Ae$uUAD&d2NVKG2|lB)Q>8g
z0Tr)v)o8X1v_3<1;p;sv=m=WZburq@7`3eA3YKslaIJ$cG}HNFy8_2ClFkGk7G9rd
zw?7}zgU3>t^|Ko3Dl-~^upNdBf-bwM%8}9qHJ`?&@T5t#OTo78>J9w7FI5=tKXqqH
zT96tfQIy$Cf%)k#ldU7n1n7J&(yB=sJW4v=x!51Vd!>n9FKtz};ISpSl>gfc~
z=ru%@m8E$PXXR2+!N;)Lmz5FCzK#KL?;2DGjioe1>`4QAm6ItpWdXN`4^7jhZfwg`
zoc-D>SrHayXUfwHYiD$j2-s||F*2#Pi4;;C?fvCI=%AF;2!n*x7naDuxx(6mJW|wp
zJ(EoIR!2s^Mz`o$4}WuKRBNO0QUXT#JB_j)2in^N$Rp#w5)7%C-Ro1AZ6b)xL+6sC
z>q3V29>5*B(d8ES=P#!&%Gn*8nv+oeE*#Da&ykXp>Z_y}uf8*>*nogao4Rs)x||-;
z9A8T#5riwJ8>RmgMNP9JtgkDryt*_qO?iuKkbA|oRZCcz2VV$QvO*DC8|&9~sn{3rYz44<4?5R=0vjwYP#y#
z_ar=^;Jl0}GDfH>0+cRKaR+Ieatv6wI-@H6%m6ml7%gF3-xozp|Axvo1+X`!AExvCgE_){<~CS_(>QG>yeJIa%@MOtTnBAt-C
zm4?q+TBbHu?X;#k(scr*o7N+zo7sXc&R~`}d)2F@w{}nQM&E07{Yeoor8)j92tC--
zO{h?|=R<~4k@AB@+I9Yi#L$W6A$U>_xU-l~LI5I4TnMwszqK)?Jw=twv3R3IEMju?
z`CRFnHBO==p>MAiDUZy^D~wD-x-Wsc`g8PY_qpx%xnQcA)!dyyEuSsjTcLe
z{eklFkkbjdpjrNh9{jRPa~oGD6ls+9Z16o@@B3&9OevMa#Y7XlS9(#drm9NfZ=~#I
z0egazSab#V4z#Qy8eu0y=QHwT(0M`D
z3i+Si!&fnykVAgHf_j$xC{E`TqV#6CrN}vc*fI4L4j63mnAk?=y*u2bkZe|yYVzXW
zT#-kR02AfAO-Mn87
zN3*SP4CR_71rak<22-V?;1DDxMGg`fKYZKQ0^ju&4@fiDVK`N^2s_2r=({B7&1$Uy
zMl(%7Fbo5^L}+xhmaG9L+*d%_?gBsFo<(6c05r<1!t3r53v1UWkCl3aaITcD6k6XO
z{k`vrQ(Yd|?dgcr-PYw_9;nK`%fMFdRg<-R@czb$COJHKu{xKKxaY{Sf)A^
zY`T}Ja8WA8Qh>mpBdSPG@oRG>W>)onXwFFKrRIB0Yl>;M))K*tq1N{)-|=WSca{*Q
zQCCnoldY+7#E6(N&*gMVxll0yI{9v8^7pViuyg$>nBY@>B9S-p(no^(r8@eND$lg!gVtDyWRrCcnJptFmi^oq<6RHwRL
zx_G4s937qoj7bxM!7F40k3^QI>*)M|7iBJir2M7=v-uk1EMHj9`Wiz|LR5b(AKLi|
zJv70l->&c)*1!Q6XD#Ehpr#f?4{>_N3XxVf4*QS
z+n2uOzj<@sJ+momO7vb_iMOI9>MiK;r3dUJVW87Nw=gHUT}2{>EzX>z9q0YAt@=9U
z;tjx35X!m-5YXD|=(@2GVrq$A=-S=rx((Y5b-1vk@TOa;9Hh3UTm_ik`|?j^qswaU
zekZPjc3cgNl0ex~Dh02b?DmN|xtb=&yk5f^DvTM0YKK~zd=plM2PR*HCSNuNsyNT7
z#T@KkSggD*Bnv&g4K!j}eLoO{5*y`gSAfk*hVwO}7lc23wS2@<_U?sPi^a3Q3s){k
zVM3l7Z%wc>8=-1<=;6_MoPvR;Keh%dNHBHoHEtc;bju6tBUbG67is|(Va5{?2iC@;
z-Xf|PIOk+e@asj3t&Ci`gPHLN&o^O!gQWJ)<2p<(c6M(kIP~L}-Ni;v@5K$td~ku<
zDQ6IfLlJFa=pZrdzaE?lms77i-`AdBnYg#b`&SJ7=O5+v0DAnA`RG2sB}!n@l+fQ;!I#ung&a?ehaO8`JNi#L4@4i+IWM?Rp-T
z!fM@gRCFYnk@T{h6Flb%;((T}95l7hBg^#nHP0Kr!KHPszxoaT=<8y*&+R3u`pkb!
z9-ZBh&zFj?2PDO#axtKo8=lrUsAT=9nZ&!**A)18`LIn%bX#6Hg52;tjsN+K2luG(
z_1x>UOH@0~9_aNvEJ@t<=~3^MlYQ!Y-pe_E&ir9LRyNm&L)nyrh=YJ(GKz`KZM(bs
z8(bm2>pR@_&p&UOTzKNpXtvy_mtJuCg5jS{Sp&D(&*oub;|Ao!1#d9{W@$IK*f(`vP!u=NES?)WW-!D3_Qvb2oEM)(qtZ8jFEKF$)~5PCr#~ES=rF;2
zG@oYz7BN`XSLCSYmSsS;F~6(?7lZREe(Xx!`f+-eyZcZp^4CIpeC5+%?AvUtMUtCz
z3Qba**C{n$@%>HlG!r@c9QVSiY)!4W&g2=?BSnp+o{f-vF;#)$(XPkx)mMQBsQ76&
z(jDcFFGR}6#RYe64kb!g%%u=7kv)l#^t^ud_p2-uR15{C47QnCo(Y=kOHRFOoQ~_&
z)HxmSd!9v7chK{-gxZ8+|(Uj_!FS>yB11
zreZqLrI_uJbT5DD5+q&4QK0n!^0A->)1l_oX9aDr?7QvFfcEhz<*ziVuYVix>EE;j+V?
zGw1qpz~PNOVB2RZ<1ggLb#ISPVc#UD$f=gyGOiV^_oSwr>4O^@$t?ygYYx1M^oci~
z5&zU&%ze#eLm%O2H>Vg%%=Dnyv?a3x$oLQSsIyFv1xE1X${EqelTQZ@>`yFe)zuAD
zAHEiy*g3;W!9h6Fz*Yise$2E7fydT3t&70Bb8>&q2S9wZdT=?B5Dymq>*G+nu#w1Q
zc2l4viuAp}UF2;DuMb46w#Ci3^iRa}2c(fx_yaDNJ(ph>9#1n9!L8+ZX5!}G=i?&P
zn%86vQC!_hhRt69vB(xFGzhLhTB3;3eM0k!bPJ|@?;||B$w~zP+0lDV15tNLeEw5X
zUK)*-VVV2GM_i7IkuKYF>5}Q`vVcnjP8DIvY{v%;K72#3-OT}iuS#;*2&s(i=e^^c
zo`%Cbj`vEZF{|kL_AFwjD7{FL*234B<2hIuc1krU@
zmM~TffHSLY8j!;bw3#s!Tu_sMj)P^Y(m<__woR>)p)tF*wx85s2o
zsy|e@q&C9moar?an5`lO$6Xk=CFJtS%pQ|Jh8)sb9|>{h#!OaN>AY~>Kw$~?<8zw+
zZA!u749UAzGUGIKn#{^+27~%!!&4@WqnISpSvV3*1Pk!Y;f<&b+U%*y-NoU3FSNIJ
z6*mM|YGURd{7e=f-`MagWD*jnfIeBGT|d1*Fn3yfRVUqI98!Pwe2LPgZsUvVm(b=T
zwULl^MdlU*l!-oCW+#^WYV|cQnas*Gp@_1|xd~yXLD5Ji*H5UPpG7Dq!lAWOSJ;Q(
zk2xaxP${@$Co5APfk)C^VJ|5}<;5L{YQyZ#L_jQ(9@P?Sbs(o{CfEWas-45nj(Ffq
zec5=d5oi;txqFoGVbpxxPb%NDnB?PCTElwU7cB4m(kl6;=h`G##^S_!7kV@x_Rckb
zC40;Z$F#nLn;vP7(bbbwJfyHvTK&7GlfppU-%DbcIPZ_pTecEq{mxPM8uzFR1CdeW
z@su>J_XI;%)iozh{Y-pfAtlQL<8Cd}V$I6jdJ7@Lxt|gX{CrfyI|jaH2!S<2
zYczX8kp)(7bmnp@qxt;5hDqWTSqPfF0AHR26VVULIk};Q;PADdeK5H5j`kUZEGX-b
zCS4iG4{#{N!ZW53sB1bCigI5SMD!65wEC6G^<*rmx`X29(22Pe
z8I4+0_6m!&zh}H9?++Qn-@nOj@;vc|65ZlTWq)?&gT4zu4oU}}F_`~7U_Zi?@KUir
zexlu~LNYJu^2#OFw>W@?A!s}uf3-#kil$=RUXW-i!=EZ)K`p|@C|9T8ij7}Yw=8=8mGkop2lBp=qujFrl_hywF+C`4SQsqP$pW8NkWZUU1e=7TTphxPthcwCY
literal 0
HcmV?d00001
diff --git a/tests/common/snappi/common_helpers.py b/tests/common/snappi/common_helpers.py
index 4a8404db1b4..f5de796dbd6 100644
--- a/tests/common/snappi/common_helpers.py
+++ b/tests/common/snappi/common_helpers.py
@@ -14,7 +14,8 @@
import ipaddr
from netaddr import IPNetwork
from tests.common.mellanox_data import is_mellanox_device as isMellanoxDevice
-
+from ipaddress import IPv6Network, IPv6Address
+from random import getrandbits
def increment_ip_address(ip, incr=1):
"""
@@ -654,3 +655,25 @@ def enable_packet_aging(duthost):
duthost.command("docker cp /tmp/packets_aging.py syncd:/")
duthost.command("docker exec syncd python /packets_aging.py enable")
duthost.command("docker exec syncd rm -rf /packets_aging.py")
+
+def get_ipv6_addrs_in_subnet(subnet, number_of_ip):
+ """
+ Get N IPv6 addresses in a subnet.
+ Args:
+ subnet (str): IPv6 subnet, e.g., '2001::1/64'
+ number_of_ip (int): Number of IP addresses to get
+ Return:
+ Return n IPv6 addresses in this subnet in a list.
+ """
+
+ subnet = str(IPNetwork(subnet).network) + "/" + str(subnet.split("/")[1])
+ subnet = unicode(subnet, "utf-8")
+ ipv6_list = []
+ for i in range(number_of_ip):
+ network = IPv6Network(subnet)
+ address = IPv6Address(
+ network.network_address + getrandbits(
+ network.max_prefixlen - network.prefixlen))
+ ipv6_list.append(str(address))
+
+ return ipv6_list
\ No newline at end of file
diff --git a/tests/common/snappi/snappi_fixtures.py b/tests/common/snappi/snappi_fixtures.py
index 0f884c39034..73fbf73edb3 100644
--- a/tests/common/snappi/snappi_fixtures.py
+++ b/tests/common/snappi/snappi_fixtures.py
@@ -3,16 +3,16 @@
"""
import pytest
import snappi
+import snappi_convergence
from ipaddress import ip_address, IPv4Address
from tests.common.fixtures.conn_graph_facts import conn_graph_facts,\
fanout_graph_facts
from tests.common.snappi.common_helpers import get_addrs_in_subnet,\
- get_peer_snappi_chassis
+ get_ipv6_addrs_in_subnet, get_peer_snappi_chassis
from tests.common.snappi.snappi_helpers import SnappiFanoutManager, get_snappi_port_location
from tests.common.snappi.port import SnappiPortConfig, SnappiPortType
from tests.common.helpers.assertions import pytest_assert
-
@pytest.fixture(scope="module")
def snappi_api_serv_ip(tbinfo):
"""
@@ -428,4 +428,97 @@ def snappi_testbed_config(conn_graph_facts,
snappi_ports=snappi_ports)
pytest_assert(config_result is True, 'Fail to configure L3 interfaces')
- return config, port_config_list
\ No newline at end of file
+ return config, port_config_list
+
+@pytest.fixture(scope="module")
+def tgen_ports(duthost,
+ conn_graph_facts,
+ fanout_graph_facts):
+
+ """
+ Populate tgen ports info of T0 testbed and returns as a list
+ Args:
+ duthost (pytest fixture): duthost fixture
+ conn_graph_facts (pytest fixture): connection graph
+ fanout_graph_facts (pytest fixture): fanout graph
+ Return:
+ [{'card_id': '1',
+ 'ip': '22.1.1.2',
+ 'ipv6': '3001::2',
+ 'ipv6_prefix': u'64',
+ 'location': '10.36.78.238;1;2',
+ 'peer_device': 'sonic-s6100-dut',
+ 'peer_ip': u'22.1.1.1',
+ 'peer_ipv6': u'3001::1',
+ 'peer_port': 'Ethernet8',
+ 'port_id': '2',
+ 'prefix': u'24',
+ 'speed': 'speed_400_gbps'},
+ {'card_id': '1',
+ 'ip': '21.1.1.2',
+ 'ipv6': '2001::2',
+ 'ipv6_prefix': u'64',
+ 'location': '10.36.78.238;1;1',
+ 'peer_device': 'sonic-s6100-dut',
+ 'peer_ip': u'21.1.1.1',
+ 'peer_ipv6': u'2001::1',
+ 'peer_port': 'Ethernet0',
+ 'port_id': '1',
+ 'prefix': u'24',
+ 'speed': 'speed_400_gbps'}]
+ """
+
+ speed_type = {'50000': 'speed_50_gbps',
+ '100000': 'speed_100_gbps',
+ '200000': 'speed_200_gbps',
+ '400000': 'speed_400_gbps'}
+
+ snappi_fanout = get_peer_snappi_chassis(conn_data=conn_graph_facts,
+ dut_hostname=duthost.hostname)
+ snappi_fanout_id = list(fanout_graph_facts.keys()).index(snappi_fanout)
+ snappi_fanout_list = SnappiFanoutManager(fanout_graph_facts)
+ snappi_fanout_list.get_fanout_device_details(device_number = snappi_fanout_id)
+ snappi_ports = snappi_fanout_list.get_ports(peer_device = duthost.hostname)
+ port_speed = None
+
+ for i in range(len(snappi_ports)):
+ if port_speed is None:
+ port_speed = int(snappi_ports[i]['speed'])
+
+ elif port_speed != int(snappi_ports[i]['speed']):
+ """ All the ports should have the same bandwidth """
+ return None
+
+ config_facts = duthost.config_facts(host=duthost.hostname,
+ source="running")['ansible_facts']
+ for port in snappi_ports:
+ port['location'] = get_snappi_port_location(port)
+ port['speed'] = speed_type[port['speed']]
+ try:
+ for port in snappi_ports:
+ peer_port = port['peer_port']
+ int_addrs = config_facts['INTERFACE'][peer_port].keys()
+ ipv4_subnet = [ele for ele in int_addrs if "." in ele][0]
+ if not ipv4_subnet:
+ raise Exception("IPv4 is not configured on the interface {}".format(peer_port))
+ port['peer_ip'], port['prefix'] = ipv4_subnet.split("/")
+ port['ip'] = get_addrs_in_subnet(ipv4_subnet, 1)[0]
+ ipv6_subnet = [ele for ele in int_addrs if ":" in ele][0]
+ if not ipv6_subnet:
+ raise Exception("IPv6 is not configured on the interface {}".format(peer_port))
+ port['peer_ipv6'], port['ipv6_prefix'] = ipv6_subnet.split("/")
+ port['ipv6'] = get_ipv6_addrs_in_subnet(ipv6_subnet, 1)[0]
+ except:
+ raise Exception('Configure IPv4 and IPv6 on DUT interfaces')
+
+ return snappi_ports
+
+
+@pytest.fixture(scope='module')
+def cvg_api(snappi_api_serv_ip,
+ snappi_api_serv_port):
+ api = snappi_convergence.api(location=snappi_api_serv_ip + ':' + str(snappi_api_serv_port),ext='ixnetwork')
+ yield api
+ if getattr(api, 'assistant', None) is not None:
+ api.assistant.Session.remove()
+
\ No newline at end of file
diff --git a/tests/snappi/bgp/__init__.py b/tests/snappi/bgp/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/snappi/bgp/files/__init__.py b/tests/snappi/bgp/files/__init__.py
new file mode 100644
index 00000000000..e69de29bb2d
diff --git a/tests/snappi/bgp/files/bgp_convergence_helper.py b/tests/snappi/bgp/files/bgp_convergence_helper.py
new file mode 100644
index 00000000000..e5152d8b1ab
--- /dev/null
+++ b/tests/snappi/bgp/files/bgp_convergence_helper.py
@@ -0,0 +1,945 @@
+from tabulate import tabulate
+from statistics import mean
+from tests.common.utilities import (wait, wait_until)
+from tests.common.helpers.assertions import pytest_assert
+logger = logging.getLogger(__name__)
+
+TGEN_AS_NUM = 65200
+DUT_AS_NUM = 65100
+TIMEOUT = 30
+BGP_TYPE = 'ebgp'
+temp_tg_port=dict()
+NG_LIST = []
+aspaths = [65002, 65003]
+
+def run_bgp_local_link_failover_test(cvg_api,
+ duthost,
+ tgen_ports,
+ iteration,
+ multipath,
+ number_of_routes,
+ route_type,
+ port_speed,):
+ """
+ Run Local link failover test
+
+ Args:
+ cvg_api (pytest fixture): snappi API
+ duthost (pytest fixture): duthost fixture
+ tgen_ports (pytest fixture): Ports mapping info of T0 testbed
+ iteration: number of iterations for running convergence test on a port
+ multipath: ecmp value for BGP config
+ number_of_routes: Number of IPv4/IPv6 Routes
+ route_type: IPv4 or IPv6 routes
+ port_speed: speed of the port used for test
+ """
+ port_count = multipath+1
+
+ """ Create bgp config on dut """
+ duthost_bgp_config(duthost,
+ tgen_ports,
+ port_count,
+ route_type,)
+
+ """ Create bgp config on TGEN """
+ tgen_bgp_config = __tgen_bgp_config(cvg_api,
+ port_count,
+ number_of_routes,
+ route_type,
+ port_speed,)
+
+ """
+ Run the convergence test by flapping all the rx
+ links one by one and calculate the convergence values
+ """
+ get_convergence_for_local_link_failover(cvg_api,
+ tgen_bgp_config,
+ iteration,
+ multipath,
+ number_of_routes,
+ route_type,)
+
+ """ Cleanup the dut configs after getting the convergence numbers """
+ cleanup_config(duthost)
+
+
+def run_bgp_remote_link_failover_test(cvg_api,
+ duthost,
+ tgen_ports,
+ iteration,
+ multipath,
+ number_of_routes,
+ route_type,
+ port_speed,):
+ """
+ Run Remote link failover test
+
+ Args:
+ cvg_api (pytest fixture): snappi API
+ duthost (pytest fixture): duthost fixture
+ tgen_ports (pytest fixture): Ports mapping info of T0 testbed
+ iteration: number of iterations for running convergence test on a port
+ multipath: ecmp value for BGP config
+ route_type: IPv4 or IPv6 routes
+ port_speed: speed of the port used for test
+ """
+ port_count = multipath+1
+ """ Create bgp config on dut """
+ duthost_bgp_config(duthost,
+ tgen_ports,
+ port_count,
+ route_type,)
+
+ """ Create bgp config on TGEN """
+ tgen_bgp_config = __tgen_bgp_config(cvg_api,
+ port_count,
+ number_of_routes,
+ route_type,
+ port_speed,)
+
+ """
+ Run the convergence test by withdrawing all the route ranges
+ one by one and calculate the convergence values
+ """
+ get_convergence_for_remote_link_failover(cvg_api,
+ tgen_bgp_config,
+ iteration,
+ multipath,
+ number_of_routes,
+ route_type,)
+
+ """ Cleanup the dut configs after getting the convergence numbers """
+ cleanup_config(duthost)
+
+
+
+def run_rib_in_convergence_test(cvg_api,
+ duthost,
+ tgen_ports,
+ iteration,
+ multipath,
+ number_of_routes,
+ route_type,
+ port_speed,):
+ """
+ Run RIB-IN Convergence test
+
+ Args:
+ cvg_api (pytest fixture): snappi API
+ duthost (pytest fixture): duthost fixture
+ tgen_ports (pytest fixture): Ports mapping info of T0 testbed
+ iteration: number of iterations for running convergence test on a port
+ multipath: ecmp value for BGP config
+ number_of_routes: Number of IPv4/IPv6 Routes
+ route_type: IPv4 or IPv6 routes
+ port_speed: speed of the port used for test
+ """
+ port_count = multipath+1
+
+ """ Create bgp config on dut """
+ duthost_bgp_config(duthost,
+ tgen_ports,
+ port_count,
+ route_type,)
+
+ """ Create bgp config on TGEN """
+ tgen_bgp_config = __tgen_bgp_config(cvg_api,
+ port_count,
+ number_of_routes,
+ route_type,
+ port_speed,)
+
+ """
+ Run the convergence test by withdrawing all routes at once and
+ calculate the convergence values
+ """
+ get_rib_in_convergence(cvg_api,
+ tgen_bgp_config,
+ iteration,
+ multipath,
+ number_of_routes,
+ route_type,)
+
+ """ Cleanup the dut configs after getting the convergence numbers """
+ cleanup_config(duthost)
+
+
+def run_RIB_IN_capacity_test(cvg_api,
+ duthost,
+ tgen_ports,
+ multipath,
+ start_value,
+ step_value,
+ route_type,
+ port_speed,):
+
+ """
+ Run RIB-IN Capacity test
+
+ Args:
+ cvg_api (pytest fixture): snappi API
+ duthost (pytest fixture): duthost fixture
+ tgen_ports (pytest fixture): Ports mapping info of T0 testbed
+ multipath: ecmp value for BGP config
+ start_value: start value of number of routes
+ step_value: step value of routes to be incremented at every iteration
+ route_type: IPv4 or IPv6 routes
+ port_speed: speed of the port used for test
+ """
+ port_count = multipath+1
+ """ Create bgp config on dut """
+ duthost_bgp_config(duthost,
+ tgen_ports,
+ port_count,
+ route_type,)
+
+
+ """ Run the RIB-IN capacity test by increasig the route count step by step """
+ get_RIB_IN_capacity(cvg_api,
+ multipath,
+ start_value,
+ step_value,
+ route_type,
+ port_speed,)
+
+ """ Cleanup the dut configs after getting the convergence numbers """
+ cleanup_config(duthost)
+
+
+def duthost_bgp_config(duthost,
+ tgen_ports,
+ port_count,
+ route_type,):
+ """
+ Configures BGP on the DUT with N-1 ecmp
+
+ Args:
+ duthost (pytest fixture): duthost fixture
+ tgen_ports (pytest fixture): Ports mapping info of T0 testbed
+ port_count:multipath + 1
+ multipath: ECMP value for BGP config
+ route_type: IPv4 or IPv6 routes
+ """
+ duthost.command("sudo config save -y")
+ duthost.command("sudo cp {} {}".format("/etc/sonic/config_db.json", "/etc/sonic/config_db_backup.json"))
+ global temp_tg_port
+ temp_tg_port = tgen_ports
+ for i in range(0, port_count):
+ intf_config = (
+ "sudo config interface ip remove %s %s/%s \n"
+ "sudo config interface ip remove %s %s/%s \n"
+ )
+ intf_config %= (tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], tgen_ports[i]['peer_port'], tgen_ports[i]['peer_ipv6'], tgen_ports[i]['ipv6_prefix'])
+ logger.info('Removing configured IP and IPv6 Address from %s' % (tgen_ports[i]['peer_port']))
+ duthost.shell(intf_config)
+
+ for i in range(0, port_count):
+ portchannel_config = (
+ "sudo config portchannel add PortChannel%s \n"
+ "sudo config portchannel member add PortChannel%s %s\n"
+ "sudo config interface ip add PortChannel%s %s/%s\n"
+ "sudo config interface ip add PortChannel%s %s/%s\n"
+ )
+ portchannel_config %= (i+1, i+1, tgen_ports[i]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['prefix'], i+1, tgen_ports[i]['peer_ipv6'], 64)
+ logger.info('Configuring %s to PortChannel%s with IPs %s,%s' % (tgen_ports[i]['peer_port'], i+1, tgen_ports[i]['peer_ip'], tgen_ports[i]['peer_ipv6']))
+ duthost.shell(portchannel_config)
+ bgp_config = (
+ "vtysh "
+ "-c 'configure terminal' "
+ "-c 'router bgp %s' "
+ "-c 'no bgp ebgp-requires-policy' "
+ "-c 'bgp bestpath as-path multipath-relax' "
+ "-c 'maximum-paths %s' "
+ "-c 'exit' "
+ )
+ bgp_config %= (DUT_AS_NUM, port_count-1)
+ duthost.shell(bgp_config)
+ if route_type == 'IPv4':
+ for i in range(1, port_count):
+ bgp_config_neighbor = (
+ "vtysh "
+ "-c 'configure terminal' "
+ "-c 'router bgp %s' "
+ "-c 'neighbor %s remote-as %s' "
+ "-c 'address-family ipv4 unicast' "
+ "-c 'neighbor %s activate' "
+ "-c 'exit' "
+ )
+ bgp_config_neighbor %= (DUT_AS_NUM, tgen_ports[i]['ip'], TGEN_AS_NUM, tgen_ports[i]['ip'])
+ logger.info('Configuring BGP v4 Neighbor %s' % tgen_ports[i]['ip'])
+ duthost.shell(bgp_config_neighbor)
+ else:
+ for i in range(1, port_count):
+ bgp_config_neighbor = (
+ "vtysh "
+ "-c 'configure terminal' "
+ "-c 'router bgp %s' "
+ "-c 'neighbor %s remote-as %s' "
+ "-c 'address-family ipv6 unicast' "
+ "-c 'neighbor %s activate' "
+ "-c 'exit' "
+ )
+ bgp_config_neighbor %= (DUT_AS_NUM, tgen_ports[i]['ipv6'], TGEN_AS_NUM, tgen_ports[i]['ipv6'])
+ logger.info('Configuring BGP v6 Neighbor %s' % tgen_ports[i]['ipv6'])
+ duthost.shell(bgp_config_neighbor)
+
+
+def __tgen_bgp_config(cvg_api,
+ port_count,
+ number_of_routes,
+ route_type,
+ port_speed,):
+ """
+ Creating BGP config on TGEN
+
+ Args:
+ cvg_api (pytest fixture): snappi API
+ port_count: multipath + 1
+ number_of_routes: Number of IPv4/IPv6 Routes
+ route_type: IPv4 or IPv6 routes
+ port_speed: speed of the port used for test
+ """
+ global NG_LIST
+ conv_config = cvg_api.convergence_config()
+ config = conv_config.config
+ for i in range(1, port_count+1):
+ config.ports.port(name='Test_Port_%d' % i, location=temp_tg_port[i-1]['location'])
+ c_lag = config.lags.lag(name="lag%d" % i)[-1]
+ lp = c_lag.ports.port(port_name='Test_Port_%d' % i)[-1]
+ lp.ethernet.name = 'lag_eth_%d' % i
+ if len(str(hex(i).split('0x')[1])) == 1:
+ m = '0'+hex(i).split('0x')[1]
+ else:
+ m = hex(i).split('0x')[1]
+ lp.protocol.lacp.actor_system_id = "00:10:00:00:00:%s" % m
+ lp.ethernet.name = "lag_Ethernet %s" % i
+ lp.ethernet.mac = "00:10:01:00:00:%s" % m
+ config.devices.device(name='Topology %d' % i)
+
+ config.options.port_options.location_preemption = True
+ layer1 = config.layer1.layer1()[-1]
+ layer1.name = 'port settings'
+ layer1.port_names = [port.name for port in config.ports]
+ layer1.ieee_media_defaults = False
+ layer1.auto_negotiation.rs_fec = True
+ layer1.auto_negotiation.link_training = False
+ layer1.speed = port_speed
+ layer1.auto_negotiate = False
+
+ def create_v4_topo():
+ eth = config.devices[0].ethernets.add()
+ eth.port_name = config.lags[0].name
+ eth.name = 'Ethernet 1'
+ eth.mac = "00:00:00:00:00:01"
+ ipv4 = eth.ipv4_addresses.add()
+ ipv4.name = 'IPv4 1'
+ ipv4.address = temp_tg_port[0]['ip']
+ ipv4.gateway = temp_tg_port[0]['peer_ip']
+ ipv4.prefix = int(temp_tg_port[0]['prefix'])
+ rx_flow_name = []
+ for i in range(2, port_count+1):
+ NG_LIST.append('Network_Group%s'%i)
+ if len(str(hex(i).split('0x')[1])) == 1:
+ m = '0'+hex(i).split('0x')[1]
+ else:
+ m = hex(i).split('0x')[1]
+
+ ethernet_stack = config.devices[i-1].ethernets.add()
+ ethernet_stack.port_name = config.lags[i-1].name
+ ethernet_stack.name = 'Ethernet %d' % i
+ ethernet_stack.mac = "00:00:00:00:00:%s" % m
+ ipv4_stack = ethernet_stack.ipv4_addresses.add()
+ ipv4_stack.name = 'IPv4 %d' % i
+ ipv4_stack.address = temp_tg_port[i-1]['ip']
+ ipv4_stack.gateway = temp_tg_port[i-1]['peer_ip']
+ ipv4_stack.prefix = int(temp_tg_port[i-1]['prefix'])
+ bgpv4 = config.devices[i-1].bgp
+ bgpv4.router_id = temp_tg_port[i-1]['peer_ip']
+ bgpv4_int = bgpv4.ipv4_interfaces.add()
+ bgpv4_int.ipv4_name = ipv4_stack.name
+ bgpv4_peer = bgpv4_int.peers.add()
+ bgpv4_peer.name = 'BGP %d' % i
+ bgpv4_peer.as_type = BGP_TYPE
+ bgpv4_peer.peer_address = temp_tg_port[i-1]['peer_ip']
+ bgpv4_peer.as_number = int(TGEN_AS_NUM)
+ route_range = bgpv4_peer.v4_routes.add(name=NG_LIST[-1]) #snappi object named Network Group 2 not found in internal db
+ route_range.addresses.add(address='200.1.0.1', prefix=32, count=number_of_routes)
+ as_path = route_range.as_path
+ as_path_segment = as_path.segments.add()
+ as_path_segment.type = as_path_segment.AS_SEQ
+ as_path_segment.as_numbers = aspaths
+ rx_flow_name.append(route_range.name)
+ return rx_flow_name
+
+ def create_v6_topo():
+ eth = config.devices[0].ethernets.add()
+ eth.port_name = config.lags[0].name
+ eth.name = 'Ethernet 1'
+ eth.mac = "00:00:00:00:00:01"
+ ipv6 = eth.ipv6_addresses.add()
+ ipv6.name = 'IPv6 1'
+ ipv6.address = temp_tg_port[0]['ipv6']
+ ipv6.gateway = temp_tg_port[0]['peer_ipv6']
+ ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix'])
+ rx_flow_name = []
+ for i in range(2, port_count+1):
+ NG_LIST.append('Network_Group%s'%i)
+ if len(str(hex(i).split('0x')[1])) == 1:
+ m = '0'+hex(i).split('0x')[1]
+ else:
+ m = hex(i).split('0x')[1]
+ ethernet_stack = config.devices[i-1].ethernets.add()
+ ethernet_stack.port_name = config.lags[i-1].name
+ ethernet_stack.name = 'Ethernet %d' % i
+ ethernet_stack.mac = "00:00:00:00:00:%s" % m
+ ipv6_stack = ethernet_stack.ipv6_addresses.add()
+ ipv6_stack.name = 'IPv6 %d' % i
+ ipv6_stack.address = temp_tg_port[i-1]['ipv6']
+ ipv6_stack.gateway = temp_tg_port[i-1]['peer_ipv6']
+ ipv6_stack.prefix = int(temp_tg_port[i-1]['ipv6_prefix'])
+
+ bgpv6 = config.devices[i-1].bgp
+ bgpv6.router_id = temp_tg_port[i-1]['peer_ip']
+ bgpv6_int = bgpv6.ipv6_interfaces.add()
+ bgpv6_int.ipv6_name = ipv6_stack.name
+ bgpv6_peer = bgpv6_int.peers.add()
+ bgpv6_peer.name = 'BGP+_%d' % i
+ bgpv6_peer.as_type = BGP_TYPE
+ bgpv6_peer.peer_address = temp_tg_port[i-1]['peer_ipv6']
+ bgpv6_peer.as_number = int(TGEN_AS_NUM)
+ route_range = bgpv6_peer.v6_routes.add(name=NG_LIST[-1])
+ route_range.addresses.add(address='3000::1', prefix=64, count=number_of_routes)
+ as_path = route_range.as_path
+ as_path_segment = as_path.segments.add()
+ as_path_segment.type = as_path_segment.AS_SEQ
+ as_path_segment.as_numbers = aspaths
+ rx_flow_name.append(route_range.name)
+ return rx_flow_name
+
+ if route_type == 'IPv4':
+ rx_flows = create_v4_topo()
+ flow = config.flows.flow(name='IPv4 Traffic')[-1]
+ elif route_type == 'IPv6':
+ rx_flows = create_v6_topo()
+ flow = config.flows.flow(name='IPv6 Traffic')[-1]
+ else:
+ raise Exception('Invalid route type given')
+ flow.tx_rx.device.tx_names = [config.devices[0].name]
+ flow.tx_rx.device.rx_names = rx_flows
+ flow.size.fixed = 1024
+ flow.rate.percentage = 100
+ flow.metrics.enable = True
+ return conv_config
+
+def get_flow_stats(cvg_api):
+ """
+ Args:
+ cvg_api (pytest fixture): Snappi API
+ """
+ request = cvg_api.convergence_request()
+ request.metrics.flow_names = []
+ return cvg_api.get_results(request).flow_metric
+
+def get_convergence_for_local_link_failover(cvg_api,
+ bgp_config,
+ iteration,
+ multipath,
+ number_of_routes,
+ route_type,):
+ """
+ Args:
+ cvg_api (pytest fixture): snappi API
+ bgp_config: __tgen_bgp_config
+ config: TGEN config
+ iteration: number of iterations for running convergence test on a port
+ number_of_routes: Number of IPv4/IPv6 Routes
+ route_type: IPv4 or IPv6 routes
+ """
+ rx_port_names = []
+ for i in range(1, len(bgp_config.config.ports)):
+ rx_port_names.append(bgp_config.config.ports[i].name)
+ bgp_config.rx_rate_threshold = 90/(multipath-1)
+ cvg_api.set_config(bgp_config)
+
+ """ Starting Protocols """
+ logger.info("Starting all protocols ...")
+ cs = cvg_api.convergence_state()
+ cs.protocol.state = cs.protocol.START
+ cvg_api.set_state(cs)
+ wait(TIMEOUT, "For Protocols To start")
+
+ def get_avg_dpdp_convergence_time(port_name):
+ """
+ Args:
+ port_name: Name of the port
+ """
+
+ table, avg, tx_frate, rx_frate, avg_delta = [], [], [], [], []
+ for i in range(0, iteration):
+ logger.info('|---- {} Link Flap Iteration : {} ----|'.format(port_name, i+1))
+
+ """ Starting Traffic """
+ logger.info('Starting Traffic')
+ cs = cvg_api.convergence_state()
+ cs.transmit.state = cs.transmit.START
+ cvg_api.set_state(cs)
+ wait(TIMEOUT, "For Traffic To start")
+ flow_stats = get_flow_stats(cvg_api)
+ tx_frame_rate = flow_stats[0].frames_tx_rate
+ assert tx_frame_rate != 0, "Traffic has not started"
+ """ Flapping Link """
+ logger.info('Simulating Link Failure on {} link'.format(port_name))
+ cs = cvg_api.convergence_state()
+ cs.link.port_names = [port_name]
+ cs.link.state = cs.link.DOWN
+ cvg_api.set_state(cs)
+ wait(TIMEOUT, "For Link to go down")
+ flows = get_flow_stats(cvg_api)
+ for flow in flows:
+ tx_frate.append(flow.frames_tx_rate)
+ rx_frate.append(flow.frames_tx_rate)
+ assert sum(tx_frate) == sum(rx_frate), "Traffic has not converged after link flap: TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate))
+ logger.info("Traffic has converged after link flap")
+ """ Get control plane to data plane convergence value """
+ request = cvg_api.convergence_request()
+ request.convergence.flow_names = []
+ convergence_metrics = cvg_api.get_results(request).flow_convergence
+ for metrics in convergence_metrics:
+ logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000))
+ avg.append(int(metrics.control_plane_data_plane_convergence_us/1000))
+ avg_delta.append(int(flows[0].frames_tx)-int(flows[0].frames_rx))
+ """ Performing link up at the end of iteration """
+ logger.info('Simulating Link Up on {} at the end of iteration {}'.format(port_name, i+1))
+ cs = cvg_api.convergence_state()
+ cs.link.port_names = [port_name]
+ cs.link.state = cs.link.UP
+ cvg_api.set_state(cs)
+ table.append('%s Link Failure' % port_name)
+ table.append(route_type)
+ table.append(number_of_routes)
+ table.append(iteration)
+ table.append(mean(avg_delta))
+ table.append(mean(avg))
+ return table
+ table = []
+ """ Iterating link flap test on all the rx ports """
+ for i, port_name in enumerate(rx_port_names):
+ table.append(get_avg_dpdp_convergence_time(port_name))
+ columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Delta Frames', 'Avg Calculated Data Convergence Time (ms)']
+ logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql"))
+
+
+def get_convergence_for_remote_link_failover(cvg_api,
+ bgp_config,
+ iteration,
+ multipath,
+ number_of_routes,
+ route_type,):
+ """
+ Args:
+ cvg_api (pytest fixture): snappi API
+ bgp_config: __tgen_bgp_config
+ config: TGEN config
+ iteration: number of iterations for running convergence test on a port
+ number_of_routes: Number of IPv4/IPv6 Routes
+ route_type: IPv4 or IPv6 routes
+ """
+ route_names = NG_LIST
+ bgp_config.rx_rate_threshold = 90/(multipath-1)
+ cvg_api.set_config(bgp_config)
+ def get_avg_cpdp_convergence_time(route_name):
+ """
+ Args:
+ route_name: name of the route
+
+ """
+ table, avg, tx_frate, rx_frate, avg_delta = [], [], [], [], []
+ """ Starting Protocols """
+ logger.info("Starting all protocols ...")
+ cs = cvg_api.convergence_state()
+ cs.protocol.state = cs.protocol.START
+ cvg_api.set_state(cs)
+ wait(TIMEOUT, "For Protocols To start")
+ for i in range(0, iteration):
+ logger.info('|---- {} Route Withdraw Iteration : {} ----|'.format(route_name, i+1))
+ """ Starting Traffic """
+ logger.info('Starting Traffic')
+ cs = cvg_api.convergence_state()
+ cs.transmit.state = cs.transmit.START
+ cvg_api.set_state(cs)
+ wait(TIMEOUT, "For Traffic To start")
+ flow_stats = get_flow_stats(cvg_api)
+ tx_frame_rate = flow_stats[0].frames_tx_rate
+ assert tx_frame_rate != 0, "Traffic has not started"
+
+ """ Withdrawing routes from a BGP peer """
+ logger.info('Withdrawing Routes from {}'.format(route_name))
+ cs = cvg_api.convergence_state()
+ cs.route.names = [route_name]
+ cs.route.state = cs.route.WITHDRAW
+ cvg_api.set_state(cs)
+ wait(TIMEOUT, "For routes to be withdrawn")
+ flows = get_flow_stats(cvg_api)
+ for flow in flows:
+ tx_frate.append(flow.frames_tx_rate)
+ rx_frate.append(flow.frames_tx_rate)
+ assert sum(tx_frate) == sum(rx_frate), "Traffic has not converged after lroute withdraw TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate))
+ logger.info("Traffic has converged after route withdraw")
+
+ """ Get control plane to data plane convergence value """
+ request = cvg_api.convergence_request()
+ request.convergence.flow_names = []
+ convergence_metrics = cvg_api.get_results(request).flow_convergence
+ for metrics in convergence_metrics:
+ logger.info('CP/DP Convergence Time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000))
+ avg.append(int(metrics.control_plane_data_plane_convergence_us/1000))
+ avg_delta.append(int(flows[0].frames_tx)-int(flows[0].frames_rx))
+ """ Advertise the routes back at the end of iteration """
+ cs = cvg_api.convergence_state()
+ cs.route.names = [route_name]
+ cs.route.state = cs.route.ADVERTISE
+ cvg_api.set_state(cs)
+ logger.info('Readvertise {} routes back at the end of iteration {}'.format(route_name, i+1))
+
+ table.append('%s route withdraw' % route_name)
+ table.append(route_type)
+ table.append(number_of_routes)
+ table.append(iteration)
+ table.append(mean(avg_delta))
+ table.append(mean(avg))
+ return table
+ table = []
+ """ Iterating route withdrawal on all BGP peers """
+ for route in route_names:
+ table.append(get_avg_cpdp_convergence_time(route))
+
+ columns = ['Event Name', 'Route Type', 'No. of Routes', 'Iterations', 'Frames Delta', 'Avg Control to Data Plane Convergence Time (ms)']
+ logger.info("\n%s" % tabulate(table, headers=columns, tablefmt="psql"))
+
+
+def get_rib_in_convergence(cvg_api,
+ bgp_config,
+ iteration,
+ multipath,
+ number_of_routes,
+ route_type,):
+ """
+ Args:
+ cvg_api (pytest fixture): snappi API
+ bgp_config: __tgen_bgp_config
+ config: TGEN config
+ iteration: number of iterations for running convergence test on a port
+ number_of_routes: Number of IPv4/IPv6 Routes
+ route_type: IPv4 or IPv6 routes
+ """
+ route_names = NG_LIST
+ bgp_config.rx_rate_threshold = 90/(multipath)
+ cvg_api.set_config(bgp_config)
+ table, avg, tx_frate, rx_frate, avg_delta = [], [], [], [], []
+ for i in range(0, iteration):
+ logger.info('|---- RIB-IN Convergence test, Iteration : {} ----|'.format(i+1))
+ """ withdraw all routes before starting traffic """
+ logger.info('Withdraw All Routes before starting traffic')
+ cs = cvg_api.convergence_state()
+ cs.route.names = route_names
+ cs.route.state = cs.route.WITHDRAW
+ cvg_api.set_state(cs)
+ wait(TIMEOUT-25, "For Routes to be withdrawn")
+ """ Starting Protocols """
+ logger.info("Starting all protocols ...")
+ cs = cvg_api.convergence_state()
+ cs.protocol.state = cs.protocol.START
+ cvg_api.set_state(cs)
+ wait(TIMEOUT, "For Protocols To start")
+ """ Start Traffic """
+ logger.info('Starting Traffic')
+ cs = cvg_api.convergence_state()
+ cs.transmit.state = cs.transmit.START
+ cvg_api.set_state(cs)
+ wait(TIMEOUT, "For Traffic To start")
+ flow_stats = get_flow_stats(cvg_api)
+ tx_frame_rate = flow_stats[0].frames_tx_rate
+ rx_frame_rate = flow_stats[0].frames_rx_rate
+ assert tx_frame_rate != 0, "Traffic has not started"
+ assert rx_frame_rate == 0
+
+ """ Advertise All Routes """
+ logger.info('Advertising all Routes from {}'.format(route_names))
+ cs = cvg_api.convergence_state()
+ cs.route.names = route_names
+ cs.route.state = cs.route.ADVERTISE
+ cvg_api.set_state(cs)
+ wait(TIMEOUT-25, "For all routes to be ADVERTISED")
+ flows = get_flow_stats(cvg_api)
+ for flow in flows:
+ tx_frate.append(flow.frames_tx_rate)
+ rx_frate.append(flow.frames_tx_rate)
+ assert sum(tx_frate) == sum(rx_frate), "Traffic has not convergedv, TxFrameRate:{},RxFrameRate:{}".format(sum(tx_frate), sum(rx_frate))
+ logger.info("Traffic has converged after route advertisement")
+
+ """ Get RIB-IN convergence """
+ request = cvg_api.convergence_request()
+ request.convergence.flow_names = []
+ convergence_metrics = cvg_api.get_results(request).flow_convergence
+ for metrics in convergence_metrics:
+ logger.info('RIB-IN Convergence time (ms): {}'.format(metrics.control_plane_data_plane_convergence_us/1000))
+ avg.append(int(metrics.control_plane_data_plane_convergence_us/1000))
+ avg_delta.append(int(flows[0].frames_tx)-int(flows[0].frames_rx))
+ """ Stop traffic at the end of iteration """
+ logger.info('Stopping Traffic at the end of iteration{}'.format(i+1))
+ cs = cvg_api.convergence_state()
+ cs.transmit.state = cs.transmit.STOP
+ cvg_api.set_state(cs)
+ wait(TIMEOUT-20, "For Traffic To stop")
+ """ Stopping Protocols """
+ logger.info("Stopping all protocols ...")
+ cs = cvg_api.convergence_state()
+ cs.protocol.state = cs.protocol.STOP
+ cvg_api.set_state(cs)
+ wait(TIMEOUT-20, "For Protocols To STOP")
+ table.append('Advertise All BGP Routes')
+ table.append(route_type)
+ table.append(number_of_routes)
+ table.append(iteration)
+ table.append(mean(avg_delta))
+ table.append(mean(avg))
+ columns = ['Event Name', 'Route Type', 'No. of Routes','Iterations', 'Frames Delta', 'Avg RIB-IN Convergence Time(ms)']
+ logger.info("\n%s" % tabulate([table], headers=columns, tablefmt="psql"))
+
+
+def get_RIB_IN_capacity(cvg_api,
+ multipath,
+ start_value,
+ step_value,
+ route_type,
+ port_speed,):
+ """
+ Args:
+ cvg_api (pytest fixture): snappi API
+ temp_tg_port (pytest fixture): Ports mapping info of T0 testbed
+ multipath: ecmp value for BGP config
+ start_value: Start value of the number of BGP routes
+ step_value: Step value of the number of BGP routes to be incremented
+ route_type: IPv4 or IPv6 routes
+ port_speed: speed of the port used in test
+ """
+ def tgen_capacity(routes):
+ conv_config = cvg_api.convergence_config()
+ config = conv_config.config
+ for i in range(1, 3):
+ config.ports.port(name='Test_Port_%d' % i, location=temp_tg_port[i-1]['location'])
+ c_lag = config.lags.lag(name="lag%d" % i)[-1]
+ lp = c_lag.ports.port(port_name='Test_Port_%d' % i)[-1]
+ lp.ethernet.name = 'lag_eth_%d' % i
+ if len(str(hex(i).split('0x')[1])) == 1:
+ m = '0'+hex(i).split('0x')[1]
+ else:
+ m = hex(i).split('0x')[1]
+ lp.protocol.lacp.actor_system_id = "00:10:00:00:00:%s" % m
+ lp.ethernet.name = "lag_Ethernet %s" % i
+ lp.ethernet.mac = "00:10:01:00:00:%s" % m
+ config.devices.device(name='Topology %d' % i)
+
+ config.options.port_options.location_preemption = True
+ layer1 = config.layer1.layer1()[-1]
+ layer1.name = 'port settings'
+ layer1.port_names = [port.name for port in config.ports]
+ layer1.ieee_media_defaults = False
+ layer1.auto_negotiation.rs_fec = True
+ layer1.auto_negotiation.link_training = False
+ layer1.speed = port_speed
+ layer1.auto_negotiate = False
+
+ def create_v4_topo():
+ eth = config.devices[0].ethernets.add()
+ eth.port_name = config.lags[0].name
+ eth.name = 'Ethernet 1'
+ eth.mac = "00:00:00:00:00:01"
+ ipv4 = eth.ipv4_addresses.add()
+ ipv4.name = 'IPv4 1'
+ ipv4.address = temp_tg_port[0]['ip']
+ ipv4.gateway = temp_tg_port[0]['peer_ip']
+ ipv4.prefix = int(temp_tg_port[0]['prefix'])
+ rx_flow_name = []
+ for i in range(2, 3):
+ if len(str(hex(i).split('0x')[1])) == 1:
+ m = '0'+hex(i).split('0x')[1]
+ else:
+ m = hex(i).split('0x')[1]
+ ethernet_stack = config.devices[i-1].ethernets.add()
+ ethernet_stack.port_name = config.lags[i-1].name
+ ethernet_stack.name = 'Ethernet %d' % i
+ ethernet_stack.mac = "00:00:00:00:00:%s" % m
+ ipv4_stack = ethernet_stack.ipv4_addresses.add()
+ ipv4_stack.name = 'IPv4 %d' % i
+ ipv4_stack.address = temp_tg_port[i-1]['ip']
+ ipv4_stack.gateway = temp_tg_port[i-1]['peer_ip']
+ ipv4_stack.prefix = int(temp_tg_port[i-1]['prefix'])
+ bgpv4 = config.devices[i-1].bgp
+ bgpv4.router_id = temp_tg_port[i-1]['peer_ip']
+ bgpv4_int = bgpv4.ipv4_interfaces.add()
+ bgpv4_int.ipv4_name = ipv4_stack.name
+ bgpv4_peer = bgpv4_int.peers.add()
+ bgpv4_peer.name = 'BGP %d' % i
+ bgpv4_peer.as_type = BGP_TYPE
+ bgpv4_peer.peer_address = temp_tg_port[i-1]['peer_ip']
+ bgpv4_peer.as_number = int(TGEN_AS_NUM)
+ route_range = bgpv4_peer.v4_routes.add(name="Network_Group%d" % i) #snappi object named Network Group 2 not found in internal db
+ route_range.addresses.add(address='200.1.0.1', prefix=32, count=number_of_routes)
+ as_path = route_range.as_path
+ as_path_segment = as_path.segments.add()
+ as_path_segment.type = as_path_segment.AS_SEQ
+ as_path_segment.as_numbers = aspaths
+ rx_flow_name.append(route_range.name)
+ return rx_flow_name
+
+ def create_v6_topo():
+ eth = config.devices[0].ethernets.add()
+ eth.port_name = config.lags[0].name
+ eth.name = 'Ethernet 1'
+ eth.mac = "00:00:00:00:00:01"
+ ipv6 = eth.ipv6_addresses.add()
+ ipv6.name = 'IPv6 1'
+ ipv6.address = temp_tg_port[0]['ipv6']
+ ipv6.gateway = temp_tg_port[0]['peer_ipv6']
+ ipv6.prefix = int(temp_tg_port[0]['ipv6_prefix'])
+ rx_flow_name = []
+ for i in range(2, 3):
+ if len(str(hex(i).split('0x')[1])) == 1:
+ m = '0'+hex(i).split('0x')[1]
+ else:
+ m = hex(i).split('0x')[1]
+ ethernet_stack = config.devices[i-1].ethernets.add()
+ ethernet_stack.port_name = config.lags[i-1].name
+ ethernet_stack.name = 'Ethernet %d' % i
+ ethernet_stack.mac = "00:00:00:00:00:%s" % m
+ ipv6_stack = ethernet_stack.ipv6_addresses.add()
+ ipv6_stack.name = 'IPv6 %d' % i
+ ipv6_stack.address = temp_tg_port[i-1]['ipv6']
+ ipv6_stack.gateway = temp_tg_port[i-1]['peer_ipv6']
+ ipv6_stack.prefix = int(temp_tg_port[i-1]['ipv6_prefix'])
+
+ bgpv6 = config.devices[i-1].bgp
+ bgpv6.router_id = temp_tg_port[i-1]['peer_ip']
+ bgpv6_int = bgpv6.ipv6_interfaces.add()
+ bgpv6_int.ipv6_name = ipv6_stack.name
+ bgpv6_peer = bgpv6_int.peers.add()
+ bgpv6_peer.name = 'BGP+_%d' % i
+ bgpv6_peer.as_type = BGP_TYPE
+ bgpv6_peer.peer_address = temp_tg_port[i-1]['peer_ipv6']
+ bgpv6_peer.as_number = int(TGEN_AS_NUM)
+ route_range = bgpv6_peer.v6_routes.add(name="Network Group %d" % i)
+ route_range.addresses.add(address='3000::1', prefix=64, count=number_of_routes)
+ as_path = route_range.as_path
+ as_path_segment = as_path.segments.add()
+ as_path_segment.type = as_path_segment.AS_SEQ
+ as_path_segment.as_numbers = aspaths
+ rx_flow_name.append(route_range.name)
+ return rx_flow_name
+ conv_config.rx_rate_threshold = 90/(multipath)
+ if route_type == 'IPv4':
+ rx_flows = create_v4_topo()
+ flow = config.flows.flow(name='IPv4_Traffic_%d' % routes)[-1]
+ elif route_type == 'IPv6':
+ rx_flows = create_v6_topo()
+ flow = config.flows.flow(name='IPv6_Traffic_%d' % routes)[-1]
+ else:
+ raise Exception('Invalid route type given')
+ flow.tx_rx.device.tx_names = [config.devices[0].name]
+ flow.tx_rx.device.rx_names = rx_flows
+ flow.size.fixed = 1024
+ flow.rate.percentage = 100
+ flow.metrics.enable = True
+ flow.metrics.loss = True
+ return conv_config
+
+ def run_traffic(routes):
+ logger.info('|-------------------- RIB-IN Capacity test, No.of Routes : {} ----|'.format(routes))
+ conv_config = tgen_capacity(routes)
+ cvg_api.set_config(conv_config)
+ """ Starting Protocols """
+ logger.info("Starting all protocols ...")
+ cs = cvg_api.convergence_state()
+ cs.protocol.state = cs.protocol.START
+ cvg_api.set_state(cs)
+ wait(TIMEOUT, "For Protocols To start")
+ """ Starting Traffic """
+ logger.info('Starting Traffic')
+ cs = cvg_api.convergence_state()
+ cs.transmit.state = cs.transmit.START
+ cvg_api.set_state(cs)
+ wait(TIMEOUT, "For Traffic To start")
+
+ try:
+ for j in range(start_value, 100000000000, step_value):
+ tx_frate, rx_frate = [], []
+ run_traffic(j)
+ flow_stats = get_flow_stats(cvg_api)
+ logger.info('Loss% : {}'.format(flow_stats[0].loss))
+ for flow in flow_stats:
+ tx_frate.append(flow.frames_tx_rate)
+ rx_frate.append(flow.frames_rx_rate)
+ logger.info("Tx Frame Rate : {}".format(tx_frate))
+ logger.info("Rx Frame Rate : {}".format(rx_frate))
+ if float(flow_stats[0].loss) > 0.001:
+ if j == start_value:
+ raise Exception('Traffic Loss Encountered in first iteration, reduce the start value and run the test')
+ logger.info('Loss greater than 0.001 occured')
+ logger.info('Reducing the routes and running test')
+ b = j-step_value
+ logger.info('Stopping Traffic')
+ cs = cvg_api.convergence_state()
+ cs.transmit.state = cs.transmit.STOP
+ cvg_api.set_state(cs)
+ wait(TIMEOUT-20, "For Traffic To stop")
+ break
+ logger.info('Stopping Traffic')
+ cs = cvg_api.convergence_state()
+ cs.transmit.state = cs.transmit.STOP
+ cvg_api.set_state(cs)
+ wait(TIMEOUT-20, "For Traffic To stop")
+ l = []
+ l.append(b+int(step_value/8))
+ l.append(b+int(step_value/4))
+ l.append(b+int(step_value/2))
+ l.append(b+step_value-int(step_value/4))
+ l.append(b+step_value-int(step_value/8))
+ for i in range(0,len(l)):
+ run_traffic(l[i])
+ flow_stats = get_flow_stats(cvg_api)
+ logger.info('Loss% : {}'.format(flow_stats[0].loss))
+ if float(flow_stats[0].loss) <= 0.001:
+ max_routes = start_value
+ pass
+ else:
+ max_routes = l[i]-int(step_value/8)
+ break
+ logger.info('Stopping Traffic')
+ cs = cvg_api.convergence_state()
+ cs.transmit.state = cs.transmit.STOP
+ cvg_api.set_state(cs)
+ wait(TIMEOUT-20, "For Traffic To stop")
+ """ Stopping Protocols """
+ logger.info("Stopping all protocols ...")
+ cs = cvg_api.convergence_state()
+ cs.protocol.state = cs.protocol.STOP
+ cvg_api.set_state(cs)
+ wait(TIMEOUT-20, "For Protocols To STOP")
+ except Exception as e:
+ logger.info(e)
+ finally:
+ columns = ['Test Name', 'Maximum no. of Routes']
+ logger.info("\n%s" % tabulate([['RIB-IN Capacity Test',max_routes]], headers=columns, tablefmt="psql"))
+
+def cleanup_config(duthost):
+ """
+ Cleaning up dut config at the end of the test
+
+ Args:
+ duthost (pytest fixture): duthost fixture
+ """
+ duthost.command("sudo cp {} {}".format("/etc/sonic/config_db_backup.json","/etc/sonic/config_db.json"))
+ duthost.shell("sudo config reload -y \n")
+ logger.info("Wait until all critical services are fully started")
+ pytest_assert(wait_until(360, 10, 1, duthost.critical_services_fully_started), "Not all critical services are fully started")
+ logger.info('Convergence Test Completed')
\ No newline at end of file
diff --git a/tests/snappi/bgp/test_bgp_local_link_failover.py b/tests/snappi/bgp/test_bgp_local_link_failover.py
new file mode 100644
index 00000000000..e1e9b31c419
--- /dev/null
+++ b/tests/snappi/bgp/test_bgp_local_link_failover.py
@@ -0,0 +1,64 @@
+from tests.common.snappi.snappi_fixtures import cvg_api
+from tests.common.snappi.snappi_fixtures import (
+ snappi_api_serv_ip, snappi_api_serv_port, tgen_ports)
+from files.bgp_convergence_helper import run_bgp_local_link_failover_test
+from tests.common.fixtures.conn_graph_facts import (
+ conn_graph_facts, fanout_graph_facts)
+import pytest
+
+
+@pytest.mark.parametrize('multipath', [2])
+@pytest.mark.parametrize('convergence_test_iterations', [1])
+@pytest.mark.parametrize('number_of_routes', [1000])
+@pytest.mark.parametrize('route_type', ['IPv4'])
+@pytest.mark.parametrize('port_speed',['speed_100_gbps'])
+def test_bgp_convergence_for_local_link_failover(cvg_api,
+ duthost,
+ tgen_ports,
+ conn_graph_facts,
+ fanout_graph_facts,
+ multipath,
+ convergence_test_iterations,
+ number_of_routes,
+ route_type,
+ port_speed,):
+
+ """
+ Topo:
+ TGEN1 --- DUT --- TGEN(2..N)
+
+ Steps:
+ 1) Create BGP config on DUT and TGEN respectively
+ 2) Create a flow from TGEN1 to (N-1) TGEN ports
+ 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range
+ 4) Simulate link failure by bringing down one of the (N-1) TGEN Ports
+ 5) Calculate the packet loss duration for convergence time
+ 6) Clean up the BGP config on the dut
+
+ Verification:
+ 1) Send traffic without flapping any link
+ Result: Should not observe traffic loss
+ 2) Flap one of the N TGEN link
+ Result: The traffic must be routed via rest of the ECMP paths
+
+ Args:
+ cvg_api (pytest fixture): Snappi Convergence API
+ duthost (pytest fixture): duthost fixture
+ tgen_ports (pytest fixture): Ports mapping info of testbed
+ conn_graph_facts (pytest fixture): connection graph
+ fanout_graph_facts (pytest fixture): fanout graph
+ multipath: ECMP value
+ convergence_test_iterations: number of iterations the link failure test has to be run for a port
+ number_of_routes: Number of IPv4/IPv6 Routes
+ route_type: IPv4 or IPv6 routes
+ port_speed: speed of the port used for test
+ """
+ #convergence_test_iterations, multipath, number_of_routes and route_type parameters can be modified as per user preference
+ run_bgp_local_link_failover_test(cvg_api,
+ duthost,
+ tgen_ports,
+ convergence_test_iterations,
+ multipath,
+ number_of_routes,
+ route_type,
+ port_speed,)
diff --git a/tests/snappi/bgp/test_bgp_remote_link_failover.py b/tests/snappi/bgp/test_bgp_remote_link_failover.py
new file mode 100755
index 00000000000..c992b061d12
--- /dev/null
+++ b/tests/snappi/bgp/test_bgp_remote_link_failover.py
@@ -0,0 +1,63 @@
+from tests.common.snappi.snappi_fixtures import cvg_api
+from tests.common.snappi.snappi_fixtures import (
+ snappi_api_serv_ip, snappi_api_serv_port, tgen_ports)
+from files.bgp_convergence_helper import run_bgp_remote_link_failover_test
+from tests.common.fixtures.conn_graph_facts import (
+ conn_graph_facts, fanout_graph_facts)
+import pytest
+
+@pytest.mark.parametrize('multipath',[2])
+@pytest.mark.parametrize('convergence_test_iterations',[1])
+@pytest.mark.parametrize('number_of_routes',[1000])
+@pytest.mark.parametrize('route_type',['IPv4'])
+@pytest.mark.parametrize('port_speed',['speed_100_gbps'])
+def test_bgp_convergence_for_remote_link_failover(cvg_api,
+ duthost,
+ tgen_ports,
+ conn_graph_facts,
+ fanout_graph_facts,
+ multipath,
+ convergence_test_iterations,
+ number_of_routes,
+ route_type,
+ port_speed,):
+
+ """
+ Topo:
+ TGEN1 --- DUT --- TGEN(2..N)
+
+ Steps:
+ 1) Create BGP config on DUT and TGEN respectively
+ 2) Create a flow from TGEN1 to (N-1) TGEN ports
+ 3) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range
+ 4) Simulate route withdraw from one of the (N-1) BGP peers which is the equivalent of remote link failure
+ 5) Calculate the cp/dp for convergence time
+ 6) Clean up the BGP config on the dut
+
+ Verification:
+ 1) Send traffic with all routes advertised by BGP peers
+ Result: Should not observe traffic loss
+ 2) Withdraw all routes from one of the BGP peer
+ Result: The traffic must be routed via rest of the ECMP paths and should not observe traffic loss
+
+ Args:
+ snappi_api (pytest fixture): Snappi API
+ duthost (pytest fixture): duthost fixture
+ tgen_ports (pytest fixture): Ports mapping info of testbed
+ conn_graph_facts (pytest fixture): connection graph
+ fanout_graph_facts (pytest fixture): fanout graph
+ multipath: ECMP value
+ convergence_test_iterations: number of iterations the cp/dp convergence test has to be run for a port
+ number_of_routes: Number of IPv4/IPv6 Routes
+ route_type: IPv4 or IPv6 routes
+ port_speed: speed of the port used for test
+ """
+ #convergence_test_iterations, multipath, number_of_routes, port_speed and route_type parameters can be modified as per user preference
+ run_bgp_remote_link_failover_test(cvg_api,
+ duthost,
+ tgen_ports,
+ convergence_test_iterations,
+ multipath,
+ number_of_routes,
+ route_type,
+ port_speed,)
diff --git a/tests/snappi/bgp/test_bgp_rib_in_capacity.py b/tests/snappi/bgp/test_bgp_rib_in_capacity.py
new file mode 100644
index 00000000000..76d79104066
--- /dev/null
+++ b/tests/snappi/bgp/test_bgp_rib_in_capacity.py
@@ -0,0 +1,64 @@
+from tests.common.snappi.snappi_fixtures import cvg_api
+from tests.common.snappi.snappi_fixtures import (
+ snappi_api_serv_ip, snappi_api_serv_port, tgen_ports)
+from files.bgp_convergence_helper import run_RIB_IN_capacity_test
+from tests.common.fixtures.conn_graph_facts import (
+ conn_graph_facts, fanout_graph_facts)
+import pytest
+
+
+@pytest.mark.parametrize('multipath', [2])
+@pytest.mark.parametrize('start_value', [1000])
+@pytest.mark.parametrize('step_value', [1000])
+@pytest.mark.parametrize('route_type', ['IPv4'])
+@pytest.mark.parametrize('port_speed',['speed_100_gbps'])
+def test_RIB_IN_capacity(cvg_api,
+ duthost,
+ tgen_ports,
+ conn_graph_facts,
+ fanout_graph_facts,
+ multipath,
+ start_value,
+ step_value,
+ route_type,
+ port_speed,):
+
+ """
+ Topo:
+ TGEN1 --- DUT --- TGEN(2..N)
+
+ Steps:
+ 1) Create a BGP config on DUT and TGEN respectively
+ 2) Create a flow from TGEN1 to TGEN2 port
+ 3) Send Traffic from TGEN1 to TGEN2 port route range
+ 4) Check if there is any loss observed
+ 5) Increment the routes in terms of step_value and repeat test untill loss is observed
+ 6) Note down the number of routes upto which no loss was observed which is the RIB-IN capacity value
+ 7) Clean up the BGP config on the dut
+ Note:
+ confihgure DUT interfaces prior to running test
+ Verification:
+ 1) Send traffic and make sure there is no loss observed
+ 2) If loss is observed quit the test and note down the maximum routes upto which there was no loss
+
+ Args:
+ snappi_api (pytest fixture): Snappi API
+ duthost (pytest fixture): duthost fixture
+ tgen_ports (pytest fixture): Ports mapping info of testbed
+ conn_graph_facts (pytest fixture): connection graph
+ fanout_graph_facts (pytest fixture): fanout graph
+ multipath: ECMP value
+ start_value: Start value of the number of BGP routes
+ step_value: Step value of the number of BGP routes to be incremented
+ route_type: IPv4 or IPv6 routes
+ port_speed: speed of the port used for test
+ """
+ #multipath, start_value, step_value and route_type, port_speed parameters can be modified as per user preference
+ run_RIB_IN_capacity_test(cvg_api,
+ duthost,
+ tgen_ports,
+ multipath,
+ start_value,
+ step_value,
+ route_type,
+ port_speed,)
diff --git a/tests/snappi/bgp/test_bgp_rib_in_convergence.py b/tests/snappi/bgp/test_bgp_rib_in_convergence.py
new file mode 100644
index 00000000000..c6f71c114ae
--- /dev/null
+++ b/tests/snappi/bgp/test_bgp_rib_in_convergence.py
@@ -0,0 +1,65 @@
+from tests.common.snappi.snappi_fixtures import cvg_api
+from tests.common.snappi.snappi_fixtures import (
+ snappi_api_serv_ip, snappi_api_serv_port, tgen_ports)
+from files.bgp_convergence_helper import run_rib_in_convergence_test
+from tests.common.fixtures.conn_graph_facts import (
+ conn_graph_facts, fanout_graph_facts)
+import pytest
+
+
+@pytest.mark.parametrize('multipath', [2])
+@pytest.mark.parametrize('convergence_test_iterations', [1])
+@pytest.mark.parametrize('number_of_routes', [1000])
+@pytest.mark.parametrize('route_type', ['IPv4'])
+@pytest.mark.parametrize('port_speed',['speed_100_gbps'])
+def test_rib_in_convergence(cvg_api,
+ duthost,
+ tgen_ports,
+ conn_graph_facts,
+ fanout_graph_facts,
+ multipath,
+ convergence_test_iterations,
+ number_of_routes,
+ route_type,
+ port_speed,):
+
+ """
+ Topo:
+ TGEN1 --- DUT --- TGEN(2..N)
+
+ Steps:
+ 1) Create BGP config on DUT and TGEN respectively
+ 2) Create a flow from TGEN1 to (N-1) TGEN ports
+ 3) Withdraw the routes from all the BGP peers
+ 4) Send Traffic from TGEN1 to (N-1) TGEN ports having the same route range
+ 4) Advertise the routes when traffic is running
+ 5) Calculate the RIB-IN convergence time
+ 6) Clean up the BGP config on the dut
+
+ Verification:
+ 1) Send traffic after withdrawing routes from all BGP peers
+ Result: Should not observe any traffic in the receiving side
+ 2) Advertise the routes when the traffic is running
+ Result: The traffic must be routed via the ECMP paths
+
+ Args:
+ snappi_api (pytest fixture): Snappi API
+ duthost (pytest fixture): duthost fixture
+ tgen_ports (pytest fixture): Ports mapping info of testbed
+ conn_graph_facts (pytest fixture): connection graph
+ fanout_graph_facts (pytest fixture): fanout graph
+ multipath: ECMP value
+ convergence_test_iterations: number of iterations the link failure test has to be run for a port
+ number_of_routes: Number of IPv4/IPv6 Routes
+ route_type: IPv4 or IPv6 routes
+ port_speed: speed of the port used for test
+ """
+ #convergence_test_iterations, multipath, number_of_routes port_speed and route_type parameters can be modified as per user preference
+ run_rib_in_convergence_test(cvg_api,
+ duthost,
+ tgen_ports,
+ convergence_test_iterations,
+ multipath,
+ number_of_routes,
+ route_type,
+ port_speed,)