PNG  IHDRX cHRMz&u0`:pQ<bKGD pHYsodtIME MeqIDATxw]Wug^Qd˶ 6`!N:!@xI~)%7%@Bh&`lnjVF29gΨ4E$|>cɚ{gk= %,a KX%,a KX%,a KX%,a KX%,a KX%,a KX%, b` ǟzeאfp]<!SJmɤY޲ڿ,%c ~ع9VH.!Ͳz&QynֺTkRR.BLHi٪:l;@(!MԴ=žI,:o&N'Kù\vRmJ雵֫AWic H@" !: Cé||]k-Ha oݜ:y F())u]aG7*JV@J415p=sZH!=!DRʯvɱh~V\}v/GKY$n]"X"}t@ xS76^[bw4dsce)2dU0 CkMa-U5tvLƀ~mlMwfGE/-]7XAƟ`׮g ewxwC4\[~7@O-Q( a*XGƒ{ ՟}$_y3tĐƤatgvێi|K=uVyrŲlLӪuܿzwk$m87k( `múcE)"@rK( z4$D; 2kW=Xb$V[Ru819קR~qloѱDyįݎ*mxw]y5e4K@ЃI0A D@"BDk_)N\8͜9dz"fK0zɿvM /.:2O{ Nb=M=7>??Zuo32 DLD@D| &+֎C #B8ַ`bOb $D#ͮҪtx]%`ES`Ru[=¾!@Od37LJ0!OIR4m]GZRJu$‡c=%~s@6SKy?CeIh:[vR@Lh | (BhAMy=݃  G"'wzn޺~8ԽSh ~T*A:xR[ܹ?X[uKL_=fDȊ؂p0}7=D$Ekq!/t.*2ʼnDbŞ}DijYaȲ(""6HA;:LzxQ‘(SQQ}*PL*fc\s `/d'QXW, e`#kPGZuŞuO{{wm[&NBTiiI0bukcA9<4@SӊH*؎4U/'2U5.(9JuDfrޱtycU%j(:RUbArLֺN)udA':uGQN"-"Is.*+k@ `Ojs@yU/ H:l;@yyTn}_yw!VkRJ4P)~y#)r,D =ě"Q]ci'%HI4ZL0"MJy 8A{ aN<8D"1#IJi >XjX֔#@>-{vN!8tRݻ^)N_╗FJEk]CT՟ YP:_|H1@ CBk]yKYp|og?*dGvzنzӴzjֺNkC~AbZƷ`.H)=!QͷVTT(| u78y֮}|[8-Vjp%2JPk[}ԉaH8Wpqhwr:vWª<}l77_~{s۴V+RCģ%WRZ\AqHifɤL36: #F:p]Bq/z{0CU6ݳEv_^k7'>sq*+kH%a`0ԣisqにtү04gVgW΂iJiS'3w.w}l6MC2uԯ|>JF5`fV5m`Y**Db1FKNttu]4ccsQNnex/87+}xaUW9y>ͯ骵G{䩓Գ3+vU}~jJ.NFRD7<aJDB1#ҳgSb,+CS?/ VG J?|?,2#M9}B)MiE+G`-wo߫V`fio(}S^4e~V4bHOYb"b#E)dda:'?}׮4繏`{7Z"uny-?ǹ;0MKx{:_pÚmFמ:F " .LFQLG)Q8qN q¯¯3wOvxDb\. BKD9_NN &L:4D{mm o^tֽ:q!ƥ}K+<"m78N< ywsard5+вz~mnG)=}lYݧNj'QJS{S :UYS-952?&O-:W}(!6Mk4+>A>j+i|<<|;ر^߉=HE|V#F)Emm#}/"y GII웻Jі94+v뾧xu~5C95~ūH>c@덉pʃ1/4-A2G%7>m;–Y,cyyaln" ?ƻ!ʪ<{~h~i y.zZB̃/,雋SiC/JFMmBH&&FAbϓO^tubbb_hZ{_QZ-sύodFgO(6]TJA˯#`۶ɟ( %$&+V'~hiYy>922 Wp74Zkq+Ovn錄c>8~GqܲcWꂎz@"1A.}T)uiW4="jJ2W7mU/N0gcqܗOO}?9/wìXžΏ0 >֩(V^Rh32!Hj5`;O28؇2#ݕf3 ?sJd8NJ@7O0 b־?lldщ̡&|9C.8RTWwxWy46ah嘦mh٤&l zCy!PY?: CJyв]dm4ǜҐR޻RլhX{FƯanшQI@x' ao(kUUuxW_Ñ줮[w8 FRJ(8˼)_mQ _!RJhm=!cVmm ?sFOnll6Qk}alY}; "baӌ~M0w,Ggw2W:G/k2%R,_=u`WU R.9T"v,<\Ik޽/2110Ӿxc0gyC&Ny޽JҢrV6N ``یeA16"J³+Rj*;BϜkZPJaÍ<Jyw:NP8/D$ 011z֊Ⱳ3ι֘k1V_"h!JPIΣ'ɜ* aEAd:ݺ>y<}Lp&PlRfTb1]o .2EW\ͮ]38؋rTJsǏP@芎sF\> P^+dYJLbJ C-xϐn> ι$nj,;Ǖa FU *择|h ~izť3ᤓ`K'-f tL7JK+vf2)V'-sFuB4i+m+@My=O҈0"|Yxoj,3]:cо3 $#uŘ%Y"y죯LebqtҢVzq¼X)~>4L׶m~[1_k?kxֺQ`\ |ٛY4Ѯr!)N9{56(iNq}O()Em]=F&u?$HypWUeB\k]JɩSع9 Zqg4ZĊo oMcjZBU]B\TUd34ݝ~:7ڶSUsB0Z3srx 7`:5xcx !qZA!;%͚7&P H<WL!džOb5kF)xor^aujƍ7 Ǡ8/p^(L>ὴ-B,{ۇWzֺ^k]3\EE@7>lYBȝR.oHnXO/}sB|.i@ɥDB4tcm,@ӣgdtJ!lH$_vN166L__'Z)y&kH;:,Y7=J 9cG) V\hjiE;gya~%ks_nC~Er er)muuMg2;֫R)Md) ,¶ 2-wr#F7<-BBn~_(o=KO㭇[Xv eN_SMgSҐ BS헃D%g_N:/pe -wkG*9yYSZS.9cREL !k}<4_Xs#FmҶ:7R$i,fi!~' # !6/S6y@kZkZcX)%5V4P]VGYq%H1!;e1MV<!ϐHO021Dp= HMs~~a)ަu7G^];git!Frl]H/L$=AeUvZE4P\.,xi {-~p?2b#amXAHq)MWǾI_r`S Hz&|{ +ʖ_= (YS(_g0a03M`I&'9vl?MM+m~}*xT۲(fY*V4x@29s{DaY"toGNTO+xCAO~4Ϳ;p`Ѫ:>Ҵ7K 3}+0 387x\)a"/E>qpWB=1 ¨"MP(\xp߫́A3+J] n[ʼnӼaTbZUWb={~2ooKױӰp(CS\S筐R*JغV&&"FA}J>G֐p1ٸbk7 ŘH$JoN <8s^yk_[;gy-;߉DV{c B yce% aJhDȶ 2IdйIB/^n0tNtџdcKj4϶v~- CBcgqx9= PJ) dMsjpYB] GD4RDWX +h{y`,3ꊕ$`zj*N^TP4L:Iz9~6s) Ga:?y*J~?OrMwP\](21sZUD ?ܟQ5Q%ggW6QdO+\@ ̪X'GxN @'4=ˋ+*VwN ne_|(/BDfj5(Dq<*tNt1х!MV.C0 32b#?n0pzj#!38}޴o1KovCJ`8ŗ_"]] rDUy޲@ Ȗ-;xџ'^Y`zEd?0„ DAL18IS]VGq\4o !swV7ˣι%4FѮ~}6)OgS[~Q vcYbL!wG3 7띸*E Pql8=jT\꘿I(z<[6OrR8ºC~ډ]=rNl[g|v TMTղb-o}OrP^Q]<98S¤!k)G(Vkwyqyr޽Nv`N/e p/~NAOk \I:G6]4+K;j$R:Mi #*[AȚT,ʰ,;N{HZTGMoּy) ]%dHء9Պ䠬|<45,\=[bƟ8QXeB3- &dҩ^{>/86bXmZ]]yޚN[(WAHL$YAgDKp=5GHjU&99v簪C0vygln*P)9^͞}lMuiH!̍#DoRBn9l@ xA/_v=ȺT{7Yt2N"4!YN`ae >Q<XMydEB`VU}u]嫇.%e^ánE87Mu\t`cP=AD/G)sI"@MP;)]%fH9'FNsj1pVhY&9=0pfuJ&gޤx+k:!r˭wkl03׼Ku C &ѓYt{.O.zҏ z}/tf_wEp2gvX)GN#I ݭ߽v/ .& и(ZF{e"=V!{zW`, ]+LGz"(UJp|j( #V4, 8B 0 9OkRrlɱl94)'VH9=9W|>PS['G(*I1==C<5"Pg+x'K5EMd؞Af8lG ?D FtoB[je?{k3zQ vZ;%Ɠ,]E>KZ+T/ EJxOZ1i #T<@ I}q9/t'zi(EMqw`mYkU6;[t4DPeckeM;H}_g pMww}k6#H㶏+b8雡Sxp)&C $@'b,fPߑt$RbJ'vznuS ~8='72_`{q纶|Q)Xk}cPz9p7O:'|G~8wx(a 0QCko|0ASD>Ip=4Q, d|F8RcU"/KM opKle M3#i0c%<7׿p&pZq[TR"BpqauIp$ 8~Ĩ!8Սx\ւdT>>Z40ks7 z2IQ}ItԀ<-%S⍤};zIb$I 5K}Q͙D8UguWE$Jh )cu4N tZl+[]M4k8֦Zeq֮M7uIqG 1==tLtR,ƜSrHYt&QP윯Lg' I,3@P'}'R˪e/%-Auv·ñ\> vDJzlӾNv5:|K/Jb6KI9)Zh*ZAi`?S {aiVDԲuy5W7pWeQJk֤#5&V<̺@/GH?^τZL|IJNvI:'P=Ϛt"¨=cud S Q.Ki0 !cJy;LJR;G{BJy޺[^8fK6)=yʊ+(k|&xQ2`L?Ȓ2@Mf 0C`6-%pKpm')c$׻K5[J*U[/#hH!6acB JA _|uMvDyk y)6OPYjœ50VT K}cǻP[ $:]4MEA.y)|B)cf-A?(e|lɉ#P9V)[9t.EiQPDѠ3ϴ;E:+Օ t ȥ~|_N2,ZJLt4! %ա]u {+=p.GhNcŞQI?Nd'yeh n7zi1DB)1S | S#ًZs2|Ɛy$F SxeX{7Vl.Src3E℃Q>b6G ўYCmtկ~=K0f(=LrAS GN'ɹ9<\!a`)֕y[uՍ[09` 9 +57ts6}b4{oqd+J5fa/,97J#6yν99mRWxJyѡyu_TJc`~W>l^q#Ts#2"nD1%fS)FU w{ܯ R{ ˎ󅃏џDsZSQS;LV;7 Od1&1n$ N /.q3~eNɪ]E#oM~}v֯FڦwyZ=<<>Xo稯lfMFV6p02|*=tV!c~]fa5Y^Q_WN|Vs 0ҘދU97OI'N2'8N֭fgg-}V%y]U4 峧p*91#9U kCac_AFңĪy뚇Y_AiuYyTTYЗ-(!JFLt›17uTozc. S;7A&&<ԋ5y;Ro+:' *eYJkWR[@F %SHWP 72k4 qLd'J "zB6{AC0ƁA6U.'F3:Ȅ(9ΜL;D]m8ڥ9}dU "v!;*13Rg^fJyShyy5auA?ɩGHRjo^]׽S)Fm\toy 4WQS@mE#%5ʈfFYDX ~D5Ϡ9tE9So_aU4?Ѽm%&c{n>.KW1Tlb}:j uGi(JgcYj0qn+>) %\!4{LaJso d||u//P_y7iRJ߬nHOy) l+@$($VFIQ9%EeKʈU. ia&FY̒mZ=)+qqoQn >L!qCiDB;Y<%} OgBxB!ØuG)WG9y(Ą{_yesuZmZZey'Wg#C~1Cev@0D $a@˲(.._GimA:uyw֬%;@!JkQVM_Ow:P.s\)ot- ˹"`B,e CRtaEUP<0'}r3[>?G8xU~Nqu;Wm8\RIkբ^5@k+5(By'L&'gBJ3ݶ!/㮻w҅ yqPWUg<e"Qy*167΃sJ\oz]T*UQ<\FԎ`HaNmڜ6DysCask8wP8y9``GJ9lF\G g's Nn͵MLN֪u$| /|7=]O)6s !ĴAKh]q_ap $HH'\1jB^s\|- W1:=6lJBqjY^LsPk""`]w)󭃈,(HC ?䔨Y$Sʣ{4Z+0NvQkhol6C.婧/u]FwiVjZka&%6\F*Ny#8O,22+|Db~d ~Çwc N:FuuCe&oZ(l;@ee-+Wn`44AMK➝2BRՈt7g*1gph9N) *"TF*R(#'88pm=}X]u[i7bEc|\~EMn}P瘊J)K.0i1M6=7'_\kaZ(Th{K*GJyytw"IO-PWJk)..axӝ47"89Cc7ĐBiZx 7m!fy|ϿF9CbȩV 9V-՛^pV̌ɄS#Bv4-@]Vxt-Z, &ֺ*diؠ2^VXbs֔Ìl.jQ]Y[47gj=幽ex)A0ip׳ W2[ᎇhuE^~q흙L} #-b۸oFJ_QP3r6jr+"nfzRJTUqoaۍ /$d8Mx'ݓ= OՃ| )$2mcM*cЙj}f };n YG w0Ia!1Q.oYfr]DyISaP}"dIӗթO67jqR ҊƐƈaɤGG|h;t]䗖oSv|iZqX)oalv;۩meEJ\!8=$4QU4Xo&VEĊ YS^E#d,yX_> ۘ-e\ "Wa6uLĜZi`aD9.% w~mB(02G[6y.773a7 /=o7D)$Z 66 $bY^\CuP. (x'"J60׿Y:Oi;F{w佩b+\Yi`TDWa~|VH)8q/=9!g߆2Y)?ND)%?Ǐ`k/sn:;O299yB=a[Ng 3˲N}vLNy;*?x?~L&=xyӴ~}q{qE*IQ^^ͧvü{Huu=R|>JyUlZV, B~/YF!Y\u_ݼF{_C)LD]m {H 0ihhadd nUkf3oٺCvE\)QJi+֥@tDJkB$1!Đr0XQ|q?d2) Ӣ_}qv-< FŊ߫%roppVBwü~JidY4:}L6M7f٬F "?71<2#?Jyy4뷢<_a7_=Q E=S1И/9{+93֮E{ǂw{))?maÆm(uLE#lïZ  ~d];+]h j?!|$F}*"4(v'8s<ŏUkm7^7no1w2ؗ}TrͿEk>p'8OB7d7R(A 9.*Mi^ͳ; eeUwS+C)uO@ =Sy]` }l8^ZzRXj[^iUɺ$tj))<sbDJfg=Pk_{xaKo1:-uyG0M ԃ\0Lvuy'ȱc2Ji AdyVgVh!{]/&}}ċJ#%d !+87<;qN޼Nفl|1N:8ya  8}k¾+-$4FiZYÔXk*I&'@iI99)HSh4+2G:tGhS^繿 Kتm0 вDk}֚+QT4;sC}rՅE,8CX-e~>G&'9xpW,%Fh,Ry56Y–hW-(v_,? ; qrBk4-V7HQ;ˇ^Gv1JVV%,ik;D_W!))+BoS4QsTM;gt+ndS-~:11Sgv!0qRVh!"Ȋ(̦Yl.]PQWgٳE'`%W1{ndΗBk|Ž7ʒR~,lnoa&:ü$ 3<a[CBݮwt"o\ePJ=Hz"_c^Z.#ˆ*x z̝grY]tdkP*:97YľXyBkD4N.C_[;F9`8& !AMO c `@BA& Ost\-\NX+Xp < !bj3C&QL+*&kAQ=04}cC!9~820G'PC9xa!w&bo_1 Sw"ܱ V )Yl3+ס2KoXOx]"`^WOy :3GO0g;%Yv㐫(R/r (s } u B &FeYZh0y> =2<Ϟc/ -u= c&׭,.0"g"7 6T!vl#sc>{u/Oh Bᾈ)۴74]x7 gMӒ"d]U)}" v4co[ ɡs 5Gg=XR14?5A}D "b{0$L .\4y{_fe:kVS\\O]c^W52LSBDM! C3Dhr̦RtArx4&agaN3Cf<Ԉp4~ B'"1@.b_/xQ} _߃҉/gٓ2Qkqp0շpZ2fԫYz< 4L.Cyυι1t@鎫Fe sYfsF}^ V}N<_`p)alٶ "(XEAVZ<)2},:Ir*#m_YӼ R%a||EƼIJ,,+f"96r/}0jE/)s)cjW#w'Sʯ5<66lj$a~3Kʛy 2:cZ:Yh))+a߭K::N,Q F'qB]={.]h85C9cr=}*rk?vwV렵ٸW Rs%}rNAkDv|uFLBkWY YkX מ|)1!$#3%y?pF<@<Rr0}: }\J [5FRxY<9"SQdE(Q*Qʻ)q1E0B_O24[U'],lOb ]~WjHޏTQ5Syu wq)xnw8~)c 쫬gٲߠ H% k5dƝk> kEj,0% b"vi2Wس_CuK)K{n|>t{P1򨾜j>'kEkƗBg*H%'_aY6Bn!TL&ɌOb{c`'d^{t\i^[uɐ[}q0lM˕G:‚4kb祔c^:?bpg… +37stH:0}en6x˟%/<]BL&* 5&fK9Mq)/iyqtA%kUe[ڛKN]Ě^,"`/ s[EQQm?|XJ߅92m]G.E΃ח U*Cn.j_)Tѧj̿30ڇ!A0=͜ar I3$C^-9#|pk!)?7.x9 @OO;WƝZBFU keZ75F6Tc6"ZȚs2y/1 ʵ:u4xa`C>6Rb/Yм)^=+~uRd`/|_8xbB0?Ft||Z\##|K 0>>zxv8۴吅q 8ĥ)"6>~\8:qM}#͚'ĉ#p\׶ l#bA?)|g g9|8jP(cr,BwV (WliVxxᡁ@0Okn;ɥh$_ckCgriv}>=wGzβ KkBɛ[˪ !J)h&k2%07δt}!d<9;I&0wV/ v 0<H}L&8ob%Hi|޶o&h1L|u֦y~󛱢8fٲUsւ)0oiFx2}X[zVYr_;N(w]_4B@OanC?gĦx>мgx>ΛToZoOMp>40>V Oy V9iq!4 LN,ˢu{jsz]|"R޻&'ƚ{53ўFu(<٪9:΋]B;)B>1::8;~)Yt|0(pw2N%&X,URBK)3\zz&}ax4;ǟ(tLNg{N|Ǽ\G#C9g$^\}p?556]/RP.90 k,U8/u776s ʪ_01چ|\N 0VV*3H鴃J7iI!wG_^ypl}r*jɤSR 5QN@ iZ#1ٰy;_\3\BQQ x:WJv츟ٯ$"@6 S#qe딇(/P( Dy~TOϻ<4:-+F`0||;Xl-"uw$Цi󼕝mKʩorz"mϺ$F:~E'ҐvD\y?Rr8_He@ e~O,T.(ފR*cY^m|cVR[8 JҡSm!ΆԨb)RHG{?MpqrmN>߶Y)\p,d#xۆWY*,l6]v0h15M˙MS8+EdI='LBJIH7_9{Caз*Lq,dt >+~ّeʏ?xԕ4bBAŚjﵫ!'\Ը$WNvKO}ӽmSşذqsOy?\[,d@'73'j%kOe`1.g2"e =YIzS2|zŐƄa\U,dP;jhhhaxǶ?КZ՚.q SE+XrbOu%\GتX(H,N^~]JyEZQKceTQ]VGYqnah;y$cQahT&QPZ*iZ8UQQM.qo/T\7X"u?Mttl2Xq(IoW{R^ ux*SYJ! 4S.Jy~ BROS[V|žKNɛP(L6V^|cR7i7nZW1Fd@ Ara{詑|(T*dN]Ko?s=@ |_EvF]׍kR)eBJc" MUUbY6`~V޴dJKß&~'d3i WWWWWW
Current Directory: /opt/imh-python/lib/python3.9/site-packages/pyroute2/iproute
Viewing File: /opt/imh-python/lib/python3.9/site-packages/pyroute2/iproute/ipmock.py
import copy import errno import queue import socket import struct from itertools import count from pyroute2.lab import LAB_API from pyroute2.netlink.exceptions import NetlinkError from pyroute2.netlink.nlsocket import NetlinkSocketBase, Stats from pyroute2.netlink.rtnl.ifaddrmsg import ifaddrmsg from pyroute2.netlink.rtnl.ifinfmsg import ifinfmsg from pyroute2.netlink.rtnl.marshal import MarshalRtnl from pyroute2.netlink.rtnl.rtmsg import rtmsg from pyroute2.requests.address import AddressFieldFilter, AddressIPRouteFilter from pyroute2.requests.link import LinkFieldFilter from pyroute2.requests.main import RequestProcessor from pyroute2.requests.route import RouteFieldFilter interface_counter = count(3) class MockLink: def __init__( self, index, ifname='', address='00:00:00:00:00:00', broadcast='ff:ff:ff:ff:ff:ff', perm_address=None, flags=1, rx_bytes=0, tx_bytes=0, rx_packets=0, tx_packets=0, mtu=0, qdisc='noqueue', kind=None, link=None, vlan_id=None, master=0, br_max_age=0, br_forward_delay=0, alt_ifname_list=None, ): self.index = index self.ifname = ifname self.flags = flags self.address = address self.broadcast = broadcast self.perm_address = perm_address self.rx_bytes = rx_bytes self.tx_bytes = tx_bytes self.rx_packets = rx_packets self.tx_packets = tx_packets self.mtu = mtu self.qdisc = qdisc self.kind = kind self.link = link self.vlan_id = vlan_id self.master = master self.br_max_age = br_max_age self.br_forward_delay = br_forward_delay self.alt_ifname_list = alt_ifname_list or [] def export(self): ret = { 'attrs': [ ['IFLA_IFNAME', self.ifname], ['IFLA_TXQLEN', 1000], ['IFLA_OPERSTATE', 'UNKNOWN'], ['IFLA_LINKMODE', 0], ['IFLA_MTU', self.mtu], ['IFLA_GROUP', 0], ['IFLA_PROMISCUITY', 0], ['IFLA_NUM_TX_QUEUES', 1], ['IFLA_GSO_MAX_SEGS', 65535], ['IFLA_GSO_MAX_SIZE', 65536], ['IFLA_GRO_MAX_SIZE', 65536], ['IFLA_NUM_RX_QUEUES', 1], ['IFLA_CARRIER', 1], ['IFLA_QDISC', self.qdisc], ['IFLA_CARRIER_CHANGES', 0], ['IFLA_CARRIER_UP_COUNT', 0], ['IFLA_CARRIER_DOWN_COUNT', 0], ['IFLA_PROTO_DOWN', 0], [ 'IFLA_MAP', { 'base_addr': 0, 'dma': 0, 'irq': 0, 'mem_end': 0, 'mem_start': 0, 'port': 0, }, ], ['IFLA_ADDRESS', self.address], ['IFLA_BROADCAST', self.broadcast], [ 'IFLA_STATS64', { 'collisions': 0, 'multicast': 0, 'rx_bytes': self.rx_bytes, 'rx_compressed': 0, 'rx_crc_errors': 0, 'rx_dropped': 0, 'rx_errors': 0, 'rx_fifo_errors': 0, 'rx_frame_errors': 0, 'rx_length_errors': 0, 'rx_missed_errors': 0, 'rx_over_errors': 0, 'rx_packets': self.rx_packets, 'tx_aborted_errors': 0, 'tx_bytes': self.tx_bytes, 'tx_carrier_errors': 0, 'tx_compressed': 0, 'tx_dropped': 0, 'tx_errors': 0, 'tx_fifo_errors': 0, 'tx_heartbeat_errors': 0, 'tx_packets': self.tx_packets, 'tx_window_errors': 0, }, ], [ 'IFLA_STATS', { 'collisions': 0, 'multicast': 0, 'rx_bytes': self.rx_bytes, 'rx_compressed': 0, 'rx_crc_errors': 0, 'rx_dropped': 0, 'rx_errors': 0, 'rx_fifo_errors': 0, 'rx_frame_errors': 0, 'rx_length_errors': 0, 'rx_missed_errors': 0, 'rx_over_errors': 0, 'rx_packets': self.rx_packets, 'tx_aborted_errors': 0, 'tx_bytes': self.tx_bytes, 'tx_carrier_errors': 0, 'tx_compressed': 0, 'tx_dropped': 0, 'tx_errors': 0, 'tx_fifo_errors': 0, 'tx_heartbeat_errors': 0, 'tx_packets': self.tx_packets, 'tx_window_errors': 0, }, ], ['IFLA_XDP', {'attrs': [['IFLA_XDP_ATTACHED', None]]}], ( 'IFLA_PERM_ADDRESS', self.perm_address if self.perm_address else self.address, ), [ 'IFLA_AF_SPEC', { 'attrs': [ [ 'AF_INET', { 'accept_local': 0, 'accept_redirects': 1, 'accept_source_route': 0, 'arp_accept': 0, 'arp_announce': 0, 'arp_ignore': 0, 'arp_notify': 0, 'arpfilter': 0, 'bootp_relay': 0, 'dummy': 65672, 'force_igmp_version': 0, 'forwarding': 1, 'log_martians': 0, 'mc_forwarding': 0, 'medium_id': 0, 'nopolicy': 1, 'noxfrm': 1, 'promote_secondaries': 1, 'proxy_arp': 0, 'proxy_arp_pvlan': 0, 'route_localnet': 0, 'rp_filter': 2, 'secure_redirects': 1, 'send_redirects': 1, 'shared_media': 1, 'src_vmark': 0, 'tag': 0, }, ] ] }, ], ], 'change': 0, 'event': 'RTM_NEWLINK', 'family': 0, 'flags': self.flags, 'header': { 'error': None, 'flags': 2, 'length': 1364, 'pid': 303471, 'sequence_number': 260, 'stats': Stats(qsize=0, delta=0, delay=0), 'target': 'localhost', 'type': 16, }, 'ifi_type': 772, 'index': self.index, 'state': 'up' if self.flags & 1 else 'down', } linkinfo = None infodata = {'attrs': []} if self.kind is not None: linkinfo = {'attrs': [('IFLA_INFO_KIND', self.kind)]} if self.kind not in (None, 'dummy'): linkinfo['attrs'].append(('IFLA_INFO_DATA', infodata)) if self.kind == 'vlan': infodata['attrs'].append(('IFLA_VLAN_ID', self.vlan_id)) ret['attrs'].append(('IFLA_LINK', self.link)) if self.kind == 'bridge': infodata['attrs'].extend( ( ('IFLA_BR_MAX_AGE', self.br_max_age), ('IFLA_BR_FORWARD_DELAY', self.br_forward_delay), ) ) if linkinfo is not None: ret['attrs'].append(('IFLA_LINKINFO', linkinfo)) if self.master != 0: ret['attrs'].append(('IFLA_MASTER', self.master)) return ret class MockAddress: def __init__( self, index, address, prefixlen, broadcast=None, label=None, family=2, local=None, **kwarg, ): self.address = address self.local = local self.broadcast = broadcast self.prefixlen = prefixlen self.index = index self.label = label self.family = family def export(self): ret = { 'family': self.family, 'prefixlen': self.prefixlen, 'flags': 0, 'scope': 0, 'index': self.index, 'attrs': [ ('IFA_ADDRESS', self.address), ('IFA_LOCAL', self.local if self.local else self.address), ('IFA_FLAGS', 512), ( 'IFA_CACHEINFO', { 'ifa_preferred': 3476, 'ifa_valid': 3476, 'cstamp': 138655779, 'tstamp': 141288674, }, ), ], 'header': { 'length': 88, 'type': 20, 'flags': 2, 'sequence_number': 256, 'pid': 320994, 'error': None, 'target': 'localhost', 'stats': Stats(qsize=0, delta=0, delay=0), }, 'event': 'RTM_NEWADDR', } if self.label is not None: ret['attrs'].append(('IFA_LABEL', self.label)) if self.broadcast is not None: ret['attrs'].append(('IFA_BROADCAST', self.broadcast)) return ret class MockRoute: def __init__( self, dst, oif, gateway=None, prefsrc=None, family=2, dst_len=24, table=254, scope=253, proto=2, route_type=1, **kwarg, ): self.dst = dst self.gateway = gateway self.prefsrc = prefsrc self.oif = oif self.family = family self.dst_len = dst_len self.table = table self.scope = scope self.proto = proto self.route_type = route_type self.priority = kwarg.get('priority', 0) self.tos = kwarg.get('tos', 0) self._type = kwarg.get('type', 2) def export(self): ret = { 'family': self.family, 'dst_len': self.dst_len, 'src_len': 0, 'tos': self.tos, 'table': self.table if self.table <= 255 else 252, 'proto': self.proto, 'scope': self.scope, 'type': self._type, 'flags': 0, 'attrs': [('RTA_TABLE', self.table), ('RTA_OIF', self.oif)], 'header': { 'length': 60, 'type': 24, 'flags': 2, 'sequence_number': 255, 'pid': 325359, 'error': None, 'target': 'localhost', 'stats': Stats(qsize=0, delta=0, delay=0), }, 'event': 'RTM_NEWROUTE', } if self.dst is not None: ret['attrs'].append(('RTA_DST', self.dst)) if self.prefsrc is not None: ret['attrs'].append(('RTA_PREFSRC', self.prefsrc)) if self.gateway is not None: ret['attrs'].append(('RTA_GATEWAY', self.gateway)) if self.priority > 0: ret['attrs'].append(('RTA_PRIORITY', self.priority)) return ret presets = { 'default': { 'links': [ MockLink( index=1, ifname='lo', address='00:00:00:00:00:00', broadcast='00:00:00:00:00:00', rx_bytes=43309665, tx_bytes=43309665, rx_packets=173776, tx_packets=173776, mtu=65536, qdisc='noqueue', ), MockLink( index=2, ifname='eth0', address='52:54:00:72:58:b2', broadcast='ff:ff:ff:ff:ff:ff', rx_bytes=175340, tx_bytes=175340, rx_packets=10251, tx_packets=10251, mtu=1500, qdisc='fq_codel', ), ], 'addr': [ MockAddress( index=1, label='lo', address='127.0.0.1', broadcast='127.255.255.255', prefixlen=8, ), MockAddress( index=2, label='eth0', address='192.168.122.28', broadcast='192.168.122.255', prefixlen=24, ), ], 'routes': [ MockRoute( dst=None, gateway='192.168.122.1', oif=2, dst_len=0, table=254, scope=0, ), MockRoute(dst='192.168.122.0', oif=2, dst_len=24, table=254), MockRoute( dst='127.0.0.0', oif=1, dst_len=8, table=255, route_type=2 ), MockRoute( dst='127.0.0.1', oif=1, dst_len=32, table=255, route_type=2 ), MockRoute( dst='127.255.255.255', oif=1, dst_len=32, table=255, route_type=3, ), MockRoute( dst='192.168.122.28', oif=2, dst_len=32, table=255, route_type=2, ), MockRoute( dst='192.168.122.255', oif=2, dst_len=32, table=255, route_type=3, ), ], }, 'netns': { 'links': [ MockLink( index=1, ifname='lo', address='00:00:00:00:00:00', broadcast='00:00:00:00:00:00', rx_bytes=43309665, tx_bytes=43309665, rx_packets=173776, tx_packets=173776, mtu=65536, qdisc='noqueue', ) ], 'addr': [ MockAddress( index=1, label='lo', address='127.0.0.1', broadcast='127.255.255.255', prefixlen=8, ) ], 'routes': [ MockRoute( dst='127.0.0.0', oif=1, dst_len=8, table=255, route_type=2 ), MockRoute( dst='127.0.0.1', oif=1, dst_len=32, table=255, route_type=2 ), MockRoute( dst='127.255.255.255', oif=1, dst_len=32, table=255, route_type=3, ), ], }, } class IPRoute(LAB_API, NetlinkSocketBase): def __init__(self, *argv, **kwarg): super().__init__() self.marshal = MarshalRtnl() self.target = kwarg.get('target') self.preset = copy.deepcopy( presets[kwarg['preset'] if 'preset' in kwarg else 'default'] ) self.buffer_queue = queue.Queue(maxsize=512) self.input_from_buffer_queue = True def bind(self, async_cache=True, clone_socket=True): pass def dump(self, groups=None): for method in (self.get_links, self.get_addr, self.get_routes): for msg in method(): yield msg def _get_dump(self, dump, msg_class): for data in dump: loader = msg_class() loader.load(data.export()) loader.encode() msg = msg_class() msg.data = loader.data msg.decode() if self.target is not None: msg['header']['target'] = self.target yield msg def _match(self, mode, obj, spec): keys = { 'address': ['address', 'prefixlen', 'index', 'family'], 'link': ['index', 'ifname'], 'route': ['dst', 'dst_len', 'oif', 'priority'], } check = False for key in keys[mode]: if key in spec: check = True if spec[key] != getattr(obj, key): return False if not check: return False return True def addr(self, command, **spec): if command == 'dump': return self.get_addr() request = RequestProcessor(context=spec, prime=spec) request.apply_filter(AddressFieldFilter()) request.apply_filter(AddressIPRouteFilter(command)) request.finalize() address = None for address in self.preset['addr']: if self._match('address', address, request): if command == 'add': raise NetlinkError(errno.EEXIST, 'address exists') break else: if command == 'del': raise NetlinkError(errno.ENOENT, 'address does not exist') address = MockAddress(**request) if command == 'add': for link in self.preset['links']: if link.index == request['index']: break else: raise NetlinkError(errno.ENOENT, 'link not found') address.label = link.ifname self.preset['addr'].append(address) for msg in self._get_dump([address], ifaddrmsg): msg.encode() self.buffer_queue.put(msg.data) elif command == 'del': self.preset['addr'].remove(address) for msg in self._get_dump([address], ifaddrmsg): msg['header']['type'] = 21 msg['event'] = 'RTM_DELADDR' msg.encode() self.buffer_queue.put(msg.data) return self._get_dump([address], ifaddrmsg) def link(self, command, **spec): if command == 'dump': return self.get_links() if 'state' in spec: spec['flags'] = 1 if spec.pop('state') == 'up' else 0 request = RequestProcessor(context=spec, prime=spec) request.apply_filter(LinkFieldFilter()) request.finalize() for interface in self.preset['links']: if self._match('link', interface, request): if command == 'add': raise NetlinkError(errno.EEXIST, 'interface exists') break else: index = next(interface_counter) if 'address' not in request: request['address'] = f'00:11:22:33:44:{index:02}' if 'index' not in request: request['index'] = index if 'tflags' in request: del request['tflags'] if 'target' in request: del request['target'] interface = MockLink(**request) if command == 'add': self.preset['links'].append(interface) for msg in self._get_dump([interface], ifinfmsg): msg.encode() self.buffer_queue.put(msg.data) elif command == 'set': for key, value in request.items(): if hasattr(interface, key): setattr(interface, key, value) for msg in self._get_dump([interface], ifinfmsg): msg.encode() self.buffer_queue.put(msg.data) return self._get_dump([interface], ifinfmsg) def route(self, command, **spec): if command == 'dump': return self.get_routes() request = RequestProcessor(context=spec, prime=spec) request.apply_filter(RouteFieldFilter()) request.finalize() for route in self.preset['routes']: if self._match('route', route, request): if command == 'add': raise NetlinkError(errno.EEXIST, 'route exists') break else: if command == 'del': raise NetlinkError(errno.ENOENT, 'route does not exist') if 'tflags' in request: del request['tflags'] if 'target' in request: del request['target'] if 'multipath' in request: del request['multipath'] if 'metrics' in request: del request['metrics'] if 'deps' in request: del request['deps'] if 'oif' not in request: (gateway,) = struct.unpack( '>I', socket.inet_aton(request['gateway']) ) for route in self.preset['routes']: if route.dst is None: continue (dst,) = struct.unpack('>I', socket.inet_aton(route.dst)) if (gateway & (0xFFFFFFFF << (32 - route.dst_len))) == dst: request['oif'] = route.oif break else: raise NetlinkError(errno.ENOENT, 'no route to the gateway') route = MockRoute(**request) if command == 'add': self.preset['routes'].append(route) for msg in self._get_dump([route], rtmsg): msg.encode() self.buffer_queue.put(msg.data) elif command == 'set': for key, value in request.items(): if hasattr(route, key): setattr(route, key, value) for msg in self._get_dump([route], rtmsg): msg.encode() self.buffer_queue.put(msg.data) elif command == 'del': self.preset['routes'].remove(route) for msg in self._get_dump([route], rtmsg): msg['header']['type'] = 25 msg['event'] = 'RTM_DELROUTE' msg.encode() self.buffer_queue.put(msg.data) return self._get_dump([route], rtmsg) def get_addr(self): return self._get_dump(self.preset['addr'], ifaddrmsg) def get_links(self): return self._get_dump(self.preset['links'], ifinfmsg) def get_routes(self): return self._get_dump(self.preset['routes'], rtmsg) class ChaoticIPRoute: def __init__(self, *argv, **kwarg): raise NotImplementedError() class RawIPRoute: def __init__(self, *argv, **kwarg): raise NotImplementedError()